我建议在Solaris上运行此操作,如果可以的话。如果您没有Solaris,请考虑使用安装Open Solaris的虚拟机。
Solaris提供了一个称为
prstat的工具。
Prstat的工作方式与大多数人熟悉的top类似。重要的区别是prstat可以为您分解进程并显示每个进程中的每个线程。
对于您的情况,使用如下命令
prstat -L 0 1
配合线程转储(最好在脚本中完成),您可以将LWPID匹配在一起,找出哪个线程是CPU占用最高的。
以下是一个功能示例(我创建了一个小应用程序进行循环)。
标准Top将显示以下内容。
PID USERNAME NLWP PRI NICE SIZE RES STATE TIME CPU COMMAND
924 username 10 59 0 31M 11M run 0:53 36.02% java
然后使用 prstat 命令如下
prstat -L 0 1 | grep java > /export/home/username/Desktop/output.txt
并且从prstat输出
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/LWPID
924 username 31M 10M run 30 0 0:00:09 35% java/10
924 username 31M 10M sleep 59 0 0:00:00 0.8% java/3
924 username 31M 10M sleep 59 0 0:00:00 0.6% java/2
924 username 31M 10M sleep 59 0 0:00:00 0.3% java/1
这看起来与顶部区别不大,但是如果你注意数据的右侧,PROCESS/LWPID会告诉你消耗CPU的Java进程中确切的线程。使用轻量级进程ID(LWPID)为10的线程正在消耗35%的CPU。如我之前所述,如果你将其与线程转储配对使用,可以找到确切的线程。对于我的情况,这是线程转储的相关部分。
"Thread-0" prio=3 tid=0x08173800 nid=0xa runnable [0xc60fc000..0xc60fcae0]
java.lang.Thread.State: RUNNABLE
at java.util.Random.next(Random.java:139)
at java.util.Random.nextInt(Random.java:189)
at ConsumerThread.run(ConsumerThread.java:13)
在线程的顶部一行,
nid 可以与 LWPID 匹配。nid=0xa (当从十六进制转换为十进制时为10)。
如果您可以将 prstat 和 thread dump 命令放到一个脚本中,并在高 CPU 使用率期间运行 4-5 次,您将开始看到模式并能够确定高 CPU 的原因。
在我的经验中,我曾经看到长时间运行的 gc 时间或 LDAP 连接配置错误导致了这个结果。祝玩得开心 :)