JVM内存溢出排查实例
问题简介
应用上线一段时间后,出现过两次运行很慢的情况,大约间隔1~2周(中间有小发布会重启应用,不能断定问题出现频率是1~2周),通过jstat –gc pid interval count查看对应的进程,看到FULL GC次数一直增长,初步判断为内存溢出问题。
保存现场
使用jmap将内存信息dump出来,语法如下:
jmap -dump:format=b,file=heap.hprof pid
分析内存
- 将dump出来的内存文件heap.hprof拷贝至本机,用Eclipse MAT插件打开。文件较大,第一次打开时需要几分钟进行分析计算,如果出身计算错误,报heap内存不够,此时需要增加eclipse的内存,配置文件位置为eclipse目录下的eclipse.ini文件;导入后的情况如下图所示:
- 查看大对象。点击图示下方的"Top Consumers"查看大对象,如下图所示:
- 查看具体对象。点击出下图所示的弹出菜单查看具体对象;
可以看到对象为com.ali.kepler.dal.dao.vo.AoneProject
- 查找源码。从源代码中,找出对AoneProject对象的引用,所有引用中,除了BuildHistoryPrepare之外,其它的引用均是使用了分页参数进行查询,如下图所示:
- 分析源码。重点分析BuildHistoryPrepare.getAoneProjectByCrid(String crid)方法
这个方法没有对crid进行非空判断,因此当crid为空时,将进行全表扫瞄,而且没有进行分页参数设置,所以最终导致内存泄漏
- 重现问题
在单元测试历史构建列表页面中,url地址栏键入回车键:
可以看到内存迅速增长,直至内存溢出
- 解决问题
- crid必须加入非空判断;
- AoneProjectDaoImpl中查询时,如果没有传入分页参数,加入分页参数;