《JVM剖析及性能跟踪》
案例2--jstack+MemoryAnalyzer分析Java进程cpu高
问题描述
线上服务器的CPU使用率自某日起逐渐升高,最终达到100%,导致服务不可用。重启机器后问题得以解决。

解决方案
为了快速恢复业务,重启了6台服务器中问题较为严重的5台,保留一台服务器进行问题分析。这一步至关重要,因为它不仅恢复了业务,还为后续排查提供了现场环境。
步骤一:定位高CPU进程
使用top命令发现Java进程(PID 384)CPU占用异常高。

步骤二:查找高CPU线程
使用top -Hp 384命令发现Java线程4430、4431、4432、4433各自占用了约40%的CPU,消耗光了CPU。

步骤三:转换线程ID
将线程ID转换为16进制:
printf "%x\n" 4430 4431 4432 4433
结果分别为114e、114f、1150、1151。
步骤四:分析线程堆栈
使用jstack -l 384 > /1.txt导出所有线程的堆栈信息,并查找这些线程的堆栈。发现这些线程均为GC线程,表明JVM内存不足,频繁进行垃圾回收,导致CPU高负荷。

步骤五:dump堆内存并分析
使用jmap命令导出堆内存数据:
sudo -u tomcat jmap -dump:live,format=b,file=/dump.dat 384
使用MemoryAnalyzer (MAT)加载堆文件,发现javax.crypto.JceSecurity对象占用了95%的内存空间。进一步分析引用树,发现BouncyCastleProvider对象持有过多,表明代码中对该对象的处理方式存在问题。需要优化我们自己的业务代码,目前已定位到问题。


结论与建议
问题的根本原因在于内存不足,导致频繁GC,而具体原因是代码中对BouncyCastleProvider的不当使用,导致内存泄漏或占用过多。建议检查代码中对该对象的使用方式,确保正确释放资源,避免内存泄漏。
通过这一案例,我们学会了使用jstack和MemoryAnalyzer工具来分析Java进程的CPU高负荷问题,并掌握了从GC线程和堆内存分析中定位问题根源的方法。