起因
上周下午,正当我准备早早下班的时候,收到了一条报警信息,XX机器的XX服务不可用,按照运维操作步骤,先把服务恢复再说,由于服务是高可用,对业务没有影响,但是还是要找出出现问题的原因,避免下次再出现。按照之前的文档处理完重启之后,需要花点时间定位一下为什么进程会退出。
日志
首先,关注是日志,在日志中,出现了下面的信息
java.lang.OutOfMemoryError: GC overhaed limit exceeded .

一般来说,导致OOM的有两种情况:
- 数据量增加,导致的堆的空间不够
- 内存泄漏,对象没有及时回收。
GC overhaed limit exceeded 一般出现的原因就是程序把JVM的内存都耗尽了,GC花费了太多的时间来回收内存,当JVM耗费了90%以上的时间却回收不回来2%的空间的时候,就会抛出这个异常。
从这里就可以知道,我们的程序里面存在没有办法回收的内存,那么是什么?
HeapDump 文件
我们的JVM程序在启动的时候,通过以下参数设置了如果出现OOM的时候就把异常dump出来。
-XX:HeapDumpOnOutOfMemeryError -XX:HeapDumpPath=$path/jvm.hprof
通过分析hprof文件就可以清楚看到存在那些内存。
jhat
一开始,我使用了jhat文件,从上面的异常我初步判断可能跟日志打印有关系,开启j

在排查一起服务因OOM崩溃的事件时,发现日志中显示GC overhead limit exceeded异常。通过设置JVM参数捕获HeapDump文件并利用jhat分析,发现在内存中的大对象主要与log4j相关。进一步研究发现,由于每个任务实例创建时都会生成不同的logName,导致LoggerManager的Hashtable中积累了大量无法释放的Logger对象,从而引发内存泄漏。解决方案是优化log4j的使用,避免过度创建Logger。
最低0.47元/天 解锁文章
8144

被折叠的 条评论
为什么被折叠?



