概述

当Java程序的CPU使用率达到100%的情况,可能是代码中存在死循环、频繁的I/O操作、不合理的锁(CAS)等问题导致。
排查问题的思路是先通过Linux命令top查看进程和线程的ID,然后把线程ID转换成16进制,最后通过java的工具jstack把栈信息打印出来,拿着16进制的线程ID找到具体的线程代码这样就能定位到具体导致cpu100%的代码了。

java程序通过docker运行,下面的命令都是基于这种环境,如果是直接部署的原理是一样的,并且下面的都是例子并不是cpu是100%

占用cpu的Java进程

如何通过top命令找到占用cpu最高的线程ID?

  1. 通过top找到java程序的进程ID是24:docker exec -it nacos top
    截屏2023-04-02 20.57.47.png
  2. 通过进程ID(24)找到进程中消耗cpu最高的线程ID(100):docker exec -it nacos top -H -p 24
    截屏2023-04-02 21.04.35.png

现在我们假如的java程序24对应的100号线程导致了cpu过高。

把线程号对应的16进制找到

使用命令printf:docker exec -it nacos printf "0x%x\n" 100 得到结果是0x64(因为jstack中的nid信息是有0x开头的所以我们直接加上了这个0x。

root@debian:~# docker exec -it nacos printf "0x%x\n" 100
0x64

最后通过jstack找到具体的进程所在的代码

注意jstack的时候参数是java主线程的ID,这样可以把所有的线程信息输出出来。

docker exec -it nacos jstack 24 | grep -C 10 0x64
// grep -C 10 是显示0x64所在行的上下10行

截屏2023-04-02 21.17.40.png

建议

Java程序中的每个线程最好都要创建线程名称,这样的话可以不通过jstack直接看到线程名字,这样在代码中可以直接找到对应的代码。