Java应用 Cpu使用率高一般排查思路(centos)

Java应用CPU使用率高一般排查思路(centos) #

一、获取cpu高的Java进程 #

登陆问题服务器,执行如下命令:

top

可以看到类似图示的结果

top进程图

  • 图中可知,CPU高的Java进程 PID = 26132

二、获取Java进程中占cpu高的若干线程id #

根据步骤一的结果 PID = 26132 执行如下命令

top -H -p 26132

可以看到图示的结果

top线程图

图中有1个线程CPU使用率最高78.7%,有8个线程cpu使用率次之,都为9%

三、找到线程对应的堆栈信息 #

取步骤二中CPU使用率最高的线程的PID(十进制)

执行如下命令

printf "%x\n" 26158

得到结果【662e】(PID的十六进制数)

此时我们已经知道了占用CPU最高的Java线程号为【662e】,然后我们需要将整个Java进程的瞬时线程堆栈dump下来,通过如下命令

jstack 26132 > threaddump.txt

然后在文件 threaddump.txt 中搜索【662e】(上面查到的占CPU高的线程),可以查到如下结果

jstack线程堆栈

可以看到,占CPU最高的线程为 “VM Thread”,VM Thread是JVM层面的一个线程,主要是负责对其他线程的创建,分配和对象的清理等工作的

从步骤二的图中,我们还可以看到,有其他8个线程,分别占了9%的使用率,取其中一个线程号进行相同操作

jstack线程堆栈2

可以看到是名为 “Gang worker#0 (Parallel GC Threads)” 的线程,这个线程是JVM用于年轻代垃圾回收(minor gc)的线程

由此可以确认该Java进程存在GC问题,需要进行进一步的GC分析

四、根据堆栈信息确认下一步排查方向 #

通常,经过上面三步的排查,可以确认找到问题线程

按照经验,问题线程可以分成以下三种:

  • 1、JVM线程
  • 2、包含业务代码堆栈的线程
  • 3、框架代码的线程(不包含业务代码堆栈的线程)

1、JVM线程 #

JIT线程 #

名称中含有 C1 CompilerThread C2 CompilerThread 的线程为即时编译(JIT)线程,如果此类线程占用CPU较高,首先可以适当添加参数 -XX:CompileThreshold 的值,减少JIT频率,C2模式下该参数默认值是10000,C1模式下默认为1500。将JIT阈值设置为20000: -XX:CompileThreshold=20000

GC线程 #

名称中含有 Gang worker#0 (Parallel GC Threads) G1 Main Concurrent Mark GC Thread Gang worker#0 (G1 Parallel Marking Threads) G1 Concurrent Refinement Thread 的线程为GC线程(此处以G1垃圾回收器举例,其他垃圾回收器线程名字有区别,详细可自行搜索)

GC线程CPU高的情况有单独的排查思路,移步 GC分析优化

2、包含业务代码堆栈的线程 #

如果问题线程堆栈中包含了业务代码(假设该线程是我们排查出来的CPU使用率高的线程),比如:

包含业务代码堆栈的线程

上述堆栈中包含了

at cn.com.duiba.duiba.test.web.controller.TestJvmController.threadTest(TestJvmController.java:37)
at cn.com.duiba.duiba.test.web.controller.TestJvmController.thread(TestJvmController.java:30)

明确指向了我们应用中的代码位置,这时就可以断定问题就是这个地方,进行代码修复即可

3、框架代码的线程(不包含业务代码堆栈的线程) #

这种情况一般比较麻烦,并且暂时没有比较通用的方法论对此问题进行覆盖

比如:问题堆栈指向lettuce框架内部的代码,这种情况一般需要先进行Google,看业界是否有其他人遇到类似的问题,如有,可以参考他们的解决方案。如没有,那么在确认自己使用方式没问题的情况下,在本地进行相关源码的debug,通过debug,对相关框架的源码进行熟悉,理解其原理,再通过其原理,推导出问题发生的原因