Java服務,有時候會遇到CPU 100%的問題,對于這樣的問題,我們如何快速定位并解決呢?一般會有如下三個步驟:
1、找到最耗CPU的進程
2、找到這個進程中最耗CPU的線程
3、查看堆棧信息,定位線程的什么操作消耗了大量CPU,定位對應代碼
下面通過一個實例來詳解一下如何快速定位CPU問題
系統:CentOS 7
模擬CPU占用偏高的測試代碼:
public class CpuUseTest {
public static void main(String[] args) {
new Thread() {
public void run() {
int result = 0;
while (true) {
result++;
if (result > Integer.MAX_VALUE / 2) {
result = 0;
}
}
}
}.start();
}
}
運行以上代碼后,通過以下幾步來查找CPU問題:
1、找到最耗CPU的進程
通過top命令查看進程的cpu占用情況,運行top命令后再鍵入P(大寫p),進程會按照CPU使用率排序,如下圖:最耗cpu進程
由上圖可以看到,最耗CPU的進程PID為2601,CPU使用率達到了100%
2、找到這個進程中最耗CPU的線程
可以使用top命令:
top -Hp ${進程的PID}
也可以使用ps命令:
ps -mp ${進程的PID} -o THREAD,tid,time
我們以top命令為例:
top -Hp 2601
運行以上命令后再鍵入P(大寫p),線程會按照CPU使用率排序,如下圖:最耗cpu線程
可以看到進程2601的最耗CPU的線程PID為2611,CPU使用率達到了99.9%
3、查看堆棧信息,定位線程的什么操作消耗了大量CPU,定位對應代碼
堆棧里,線程id是用16進制表示的,所以需要將線程PID轉化為16進制:
printf "%x\n" 2611
輸出:
a33
打印進程堆棧信息(注意2601是進程的PID),通過線程id,過濾得到線程堆棧:
jstack 2601 | grep a33 -A 20
輸出信息如下:堆棧信息
由此可以看到,最耗CPU的代碼為CpuUseTest.java代碼中的第9行,也就是執行無限循環的代碼塊所在的位置。
直此導致該應用CPU偏高的問題,被成功定位。
4、查看堆棧信息中遇到的問題
剛開始查看堆棧信息的時候,使用了如下命令(請跟上面的命令對比一下,看看有什么不同):
jstack 2611 | grep a33 -A 20
結果報錯:堆棧信息報錯
是的,我把該寫進程PID的地方,寫成了線程PID,找了一圈,才解決這個問題,也耗費了不少時間。