事件描述
12月17日、18日合同子系统各崩溃一次,通过分析和检查代码发现代码存在内存泄漏问题,于12月19日修复并彻底排除该故障隐患。
问题追踪
导致内存泄漏问题是使用XDocreport插件生成合同文件时默认使用了缓存,该缓存是无法自动释放内存,造成内存泄漏。
排查过程
1. 定位进程ID
ps -ef|grep 进程名关键词
按照进程的名称定位进场id=441
2. 查看GC情况
jstat -gcutil 441 3000
每间隔3秒打印一次GC情况
E区O区内存都打满了,每3秒内出现2次FGC
3. 查看内存对象数量
jmap -histo:live 441|head 20
查看进程前20的对象占用数量,占用对象XReportCache数量占用数量高
4. 重启生产进程
增加JVM参数:-XX:HeapDumpOutOfMemoryError -XX:HeapDumpPath=/data/dump 当堆内存溢出时打印Dump文件
5. 测试环境复现
针对生成合同文件功能进行压测 测试环境进行复现成功,使用Eclipse的MAT进行分析:
结论是XReportCache持有的对象数量过多,占了74%以上
6. 代码分析
生成合同文件方法,首先单例获取XDocReportRegistry,调用loadReport方法。
单例XDocReportRegistry持有一个缓存对象ICacheStorage。
生成PDF文档时调用loadReport方法,参数cacheReport=true,默认是缓存Report。
此时,每次调用将缓存数据
缓存的实现MapCacheStorager,本质一个hashMap,不会主动释放。需要remove或clear方法释放。
问题修复
缓存的report实际并没有用到,所以使用loadReport的重载方法,不使用缓存,问题解决。