JVM调优定位最耗cpu的线程
jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有 ps、top、printf、jstack、grep。
第一步先找出Java进程ID
可以通过 jps 或 ps -ef|grep java找到 java进程;
[root@redis webapps]# jps
2403 NameNode
22272 Bootstrap
17019 Jps
得到进程ID为22272
第二步找出该进程内最耗费CPU的线程
可以使用
1)ps -Lfp pid
2)ps -mp pid -o THREAD, tid, time
3)top -Hp pid
用第三个,输出如下:
[root@redis webapps]# top -Hp 22272
top - 10:09:30 up 9 days, 22:10, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 30 total, 0 running, 30 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 3923196k total, 3795588k used, 127608k free, 153056k buffers
Swap: 6160376k total, 0k used, 6160376k free, 3079244k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22272 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22278 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22279 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22282 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22283 root 20 0 2286m 122m 11m S 0.0 3.2 3:01.48 java
22287 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22288 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22289 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
22290 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.03 java
22291 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.34 java
22292 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.06 java
22299 root 20 0 2286m 122m 11m S 0.0 3.2 0:06.37 java
22301 root 20 0 2286m 122m 11m S 0.0 3.2 1:09.73 java
17034 root 20 0 2286m 122m 11m S 0.0 3.2 0:00.00 java
TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为22283 的线程
第三步获取线程id的十六进制码
用 printf “%x\n” 22283
[root@redis webapps]# printf ‘%x\n’ 22283
570b
得到22283 的十六进制值为570b。
第四步使用jstack获取堆栈信息
下一步轮到jstack上场了,它用来输出进程22272 的堆栈信息,然后根据线程ID的十六进制值grep,如下:
[root@redis webapps]# jstack 22272 | grep 570b
“SchedulerThread” prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()
可以看到CPU消耗在SchedulerThread这个类的Object.wait(),定位到下面的代码:
// Idle wait
synchronized(sigLock) {
try {
if(!halted.get()) {
sigLock.wait(timeUntilContinue);
}
}
catch (InterruptedException ignore) {
}
}
它是轮询任务的空闲等待代码,上面的sigLock.wait(timeUntilContinue)就对应了前面的Object.wait()。
也可以通过 jstack导出所有堆栈信息,根据线程ID的十六进制值找到该线程的堆栈信息,通过该信息分析其使用情况。