在開發(fā)過程中,有時候我們發(fā)現(xiàn)JVM占用的CPU居高不下宣谈,跟我們的預(yù)期不符愈犹,這時,CPU在做什么呢闻丑?是什么線程讓CPU如此忙碌呢漩怎?我們通過如下幾步,可以查看CPU在執(zhí)行什么線程嗦嗡。
1.查找jvm進(jìn)程ID: jps -lv 或者 ps aux | grep java
2.根據(jù)pid勋锤,查找占用cpu較高的線程:ps -mp <pid> -o THREAD,tid,time | sort -k2r
命令查看,后面的sort參數(shù)根據(jù)線程占用的cpu比例進(jìn)行排序:
3.將tid轉(zhuǎn)換為16進(jìn)制的數(shù)字:
printf “%x\n” tid
4.因為thread id在棧信息中是以十六進(jìn)制的形式顯示的侥祭,因此需要使用 printf "%x \n" <tid>
命令將現(xiàn)場id轉(zhuǎn)成十六進(jìn)制的值叁执,然后執(zhí)行jstack -l <pid> | grep <thread-hex-id> -A 10
命令顯示出錯的堆棧信息茄厘,從而定位到具體線程和代碼如下圖:
jstack:在JDK5開始提供的內(nèi)置工具,可以打印指定進(jìn)程中線程運行的狀態(tài)徒恋,包括線程數(shù)量蚕断、是否存在死鎖欢伏、資源競爭情況和線程的狀態(tài)等等入挣。有下面的幾個常用的參數(shù):
-l 長列表,打印關(guān)于鎖的附加信息
-m 打印java和jni框架的所有棧信息
上面命令中 -A 10
參數(shù)用來指定顯示行數(shù)硝拧,否則只會顯示一行信息径筏。
這樣通過上圖,可以很快地定位到程序問題的代碼障陶,然后對代碼進(jìn)行分析和改進(jìn)即可滋恬。注意:需要在多個時間段提出多個 Thread Dump信息,然后綜合進(jìn)行對比分析抱究,單獨分析一個文件是沒有意義的恢氯。
這樣,你就看到CPU這么高鼓寺,是什么線程在搗亂了勋拟!
上面講述了整個的分析過程,不過所有的命令就是實時的妈候,所以最好創(chuàng)建一個shell腳本瞬間執(zhí)行完成:
#!/bin/bash
#
# 當(dāng)JVM占用CPU特別高時敢靡,查看CPU正在做什么
# 可輸入兩個參數(shù):1、pid Java進(jìn)程ID苦银,必須參數(shù) 2啸胧、打印線程ID上下文行數(shù),可選參數(shù)幔虏,默認(rèn)打印10行
#
pid=$1
if test -z $pid
then
echo "pid can not be null!"
exit
else
echo "checking pid($pid)"
fi
if test -z "$(jps -l | cut -d '' -f 1 | grep $pid)"
then
echo "process of $pid is not exists"
exit
fi
lineNum=$2
if test -z $lineNum
then
$lineNum=10
fi
jstack $pid >> "$pid".bak
ps -mp $pid -o THREAD,tid,time | sort -k2r | awk '{if ($1 !="USER" && $2 != "0.0" && $8 !="-") print $8;}' | xargs printf "%x\n" >> "$pid".tmp
tidArray="$( cat $pid.tmp)"
for tid in $tidArray
do
echo "******************************************************************* ThreadId=$tid **************************************************************************"
cat "$pid".bak | grep $tid -A $lineNum
done
rm -rf $pid.bak
rm -rf $pid.tmp