《JVM剖析及性能跟踪》
案例1--jstack检测Java进程cpu高
问题描述
在生产环境中,我们遇到了一个Java进程CPU使用率达到100%的问题,导致线上服务不可用。经过初步排查,我们决定重启两台服务器中问题较为严重的那一台,以快速恢复业务。同时,我们保留了另一台服务器的现场,以便进一步分析问题的根本原因。这种做法在故障处理中非常重要,因为它不仅保证了业务的快速恢复,还为后续的故障排查提供了必要的条件。
步骤一:查看哪个进程的CPU占用高
我们首先使用top命令来查看系统中各个进程的CPU使用情况。通过执行以下命令,我们发现Java进程的PID为17850,并且它占用了100%的CPU资源。
top

步骤二:查看CPU占用高的线程
为了进一步确定是哪个线程导致了高CPU usage,我们使用了top命令的线程视图。通过执行以下命令,我们找到了具体的线程ID(TID)为17880,该线程占用了100%的CPU。
top -H -p 17850

步骤三:转换线程ID
由于jstack命令需要十六进制的线程ID,我们使用printf命令将十进制的线程ID转换为十六进制。
printf "%x\n" 17880
结果显示为45d8。
步骤四:定位哪个线程CPU占用高
接下来,我们使用jstack命令来获取Java进程的线程堆栈信息,并通过grep命令过滤出我们关注的线程。
jstack 17850 | grep 45d8 -A 30
通过分析线程堆栈信息,我们发现高CPU usage的线程正在执行com.demo.guava.HardTask.call方法的第18行代码。这表明该方法中可能存在计算密集型操作或不必要的循环,导致CPU usage过高。
而com.demo.* 这个包,正是我们项目的包名,看来出问题的代码就是我们自己写的。而且本次是在生产环境定位的代码问题点。真是一次成功的经历。

结论
通过上述步骤,我们成功地定位了导致Java进程CPU usage过高的具体线程和代码位置。接下来,我们可以针对com.demo.guava.HardTask.call方法进行优化,以降低CPU usage,提高系统的性能和稳定性。
最佳实践
- 保留现场:在生产环境中,保留一台出现问题的服务器,以便进行深入分析,这是故障排查的重要步骤。
- 使用工具:熟练使用如
top、jstack等工具,可以帮助我们快速定位问题。 - 代码审查:定期审查代码,特别是计算密集型操作,以避免类似的性能问题。
通过这些方法和工具,我们可以更有效地诊断和解决Java应用程序中的性能问题。