最近重构服务项目,已经上线了一个多月了,突然这两天收到服务监控报警短信显示jvm_old过高,然后经过一系列的排查定位到问题并解决的过程分享下。
监控短信
1、首先登录到所在服务机器top命令找出占用cpu最高的进程Id
查看占用cpu较高的进程
2、查看进程中占用cpu过高的线程Id
1451在线10进制转换16进制为5ab
3、使用jstack 1422[进程Id] > jstack_01打印堆栈信息,下载到本地,然后在文件里搜索线程id16进制的线程
可以发现是VM线程在gc
4、使用jstat -gcutil 1422[pid] 1000[毫秒数]打印gc信息
此图发现old区都已经接近100%
大概说一下,S0,S1这些参数代表的含义
到这里基本确定就是Full gc太频繁导致机器old区过高
5、确定问题了,现在要定位具体代码的问题,只能查看堆内存采用mat(Memory Analyzer tool)工具来分析
命令:jmap -dump:format=b,file=文件路径/dumpfile.hprof 1422
文件有八百多M,下载到本地
6、下载mat工具,下载链接地址:http://www.eclipse.org/mat/downloads.php
下载直接解压就可以
7、打开MemoryAnalyzer.exe,直接File > Open Heap dump > 选择下载的dump文件
直接点击Leak Suspects
查看内存泄露的报告,点击Details 往下拉查看具体的线程
打开红框的线程
没办法截图用手机拍的
打开上图红框,再点击下图红框视角,可以得到如下图
点击红框视角
到这里基本确认是线程全部在创建esb消息,old区无法及时回收导致cpu过高。由于重构项目接口暂时还不多,马上就定位到了项目中的问题代码。问题代码为发送异步消息时每次重新创建发送对象,及时修复解决上线,再观察发现cpu占用恢复正常。需要总结的是写代码的时候一定要注意质量,而且需要快速定位问题才能保证服务的稳定性。