定位过程:
CPU飙升问题定位的一般步骤是:
-
首先通过top指令查看当前占用CPU较高的进程PID;
-
查看当前进程消耗资源的线程PID:top -Hp PID
-
通过print命令将线程PID转为16进制,根据该16进制值去打印的堆栈日志内查询,查看该线程所驻留的方法位置。
-
通过jstack命令,查看栈信息,定位到线程对应的具体代码。
-
分析代码解决问题。
处理过程:
-
如果是空循环,或者空自旋。
处理方式:可以使用Thread.sleep或者加锁,让线程适当的阻塞。
-
在循环的代码逻辑中,创建大量的新对象导致频繁GC。比如,从mysql查出了大量的数据,比如100W以上等等。
处理方式:可以减少对象的创建数量,或者,可以考虑使用 对象池。
下面列举一个详细的例子:
登录服务器,执行top命令,查看CPU占用情况,可以看到一个java进程占用cpu一直在%40左右
很容易发现,PID为2156的java进程的CPU飙升到700%多,且一直降不下来,很显然出现了问题。
使用top -Hp命令定位线程
使用 top -Hp命令(为Java进程的id号)查看该Java进程内所有线程的资源占用情况(按shft+p按照cpu占用进行排序,按shift+m按照内存占用进行排序)
此处按照cpu排序:
top -Hp 2156
很容易发现,线程256的CPU占用达到了%40多。我们挑选线程号为2156的线程继续分析。
注意此处的2156是进程2756的一个线程。
使用jstack命令定位代码
1.线程号转换5为16进制
printf “%x\n” 命令(tid指线程的id号)将以上10进制的线程号转换为16进制:
3.根据线程号定位具体代码
在jstack_result.txt 文件中根据线程好nid搜索对应的线程描述
转换后的结果分别为ac4,由于导出的线程快照中线程的nid是16进制的,而16进制以0x开头,所以对应的16进制的线程号nid为0xac4
2.采用jstack命令导出线程快照
通过使用dk自带命令jstack获取该java进程的线程快照并输入到文件中:
jstack -l 进程ID > ./jstack_result.txt
3.根据线程号定位具体代码
在jstack_result.txt 文件中根据线程好nid搜索对应的线程描述
cat jstack_result.txt |grep -A 100 ac4
从此处可以看出,我们代码的具体的堆栈信息:
找到了代码的具体行数,com.wl.test.controller.testController.mdStream(testController.java:23)
可以看出:当前代码中我们写了一个死循环。所以导致了cpu飙高。至此问题找到。
点点赞点点关注呀,持续分享有用的知识........................