Java实战:一次生产OOM排查过程

351 阅读2分钟

事件描述

12月17日、18日合同子系统各崩溃一次,通过分析和检查代码发现代码存在内存泄漏问题,于12月19日修复并彻底排除该故障隐患。

问题追踪

导致内存泄漏问题是使用XDocreport插件生成合同文件时默认使用了缓存,该缓存是无法自动释放内存,造成内存泄漏。

排查过程

1. 定位进程ID

ps -ef|grep 进程名关键词

按照进程的名称定位进场id=441

2. 查看GC情况

jstat -gcutil 441 3000 每间隔3秒打印一次GC情况

1735739442866.jpg

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进行分析:

1735740317725.jpg

结论是XReportCache持有的对象数量过多,占了74%以上

6. 代码分析

生成合同文件方法,首先单例获取XDocReportRegistry,调用loadReport方法。

-1.jpg

单例XDocReportRegistry持有一个缓存对象ICacheStorage。 1.jpg

生成PDF文档时调用loadReport方法,参数cacheReport=true,默认是缓存Report。 03.jpg

此时,每次调用将缓存数据

4.jpg

缓存的实现MapCacheStorager,本质一个hashMap,不会主动释放。需要remove或clear方法释放。 5-1.jpg

问题修复

缓存的report实际并没有用到,所以使用loadReport的重载方法,不使用缓存,问题解决。

10.jpg