记一次OOM处理过程:OutOfMemoryError: Java heap space

项目上在使用系统的某个功能时,系统报错,日志显示 OutOfMemoryError: Java heap space

内存溢出了,接下来就要分析原因了。从客户现场要来了错误日志、线程堆栈状态信息以及OOM时的JVM内存快照(可通过启动命令中加 -XX:+HeapDumpOnOutOfMemoryError  ,在发生OOM时自动dump内存状态)。

问题排查:

首先通过错误日志定位到本次操作的是系统的数据导出功能的代码,该处代码是使用阿里的fastjson对自定义的一个对象转换成byte[]。

byte[] bytes = JSON.toJSONBytes(stuff, SerializerFeature.BrowserCompatible,
                SerializerFeature.WriteClassName);

具体定位到fastjson内部代码位置,如下:

记一次OOM处理过程:OutOfMemoryError: Java heap space_第1张图片

记一次OOM处理过程:OutOfMemoryError: Java heap space_第2张图片

可以发现是在转换过程中,数组扩容导致的。询问客户运维,通过  jmap -heap pid 得到系统运行的内存设置,发现项目上设置的MaxHeapSize是3G,是符合我们的系统要求的。这是怎么回事呢? 这个问题在其他项目上也是从来没有出现过的,所以目前只好把这个作为初步原因,继续排查。

然后分析了堆栈信息,并没有发现异常情况。

最后来分析内存快照,使用Memory Analyzer Tool(MAT)打开了文件,但是分析后只是有两个较大的对象分别是50多M和20多M,看起来并不是这两个引起的。

记一次OOM处理过程:OutOfMemoryError: Java heap space_第3张图片

然而同事使用 IBM Memory Analyzer打开快照文件后, 发现其中有一个 1.7G的大数组!! 至于为什么两个工具分析的结果不同,目前也不知道原因。不过通过这个大数组和前面报错代码位置,基本可用确定就是在数组扩容时内存溢出了。

然后本人通过使用jdk自带工具jmc.exe(也可以用jvisualvm),在开发环境调试了下,监控内存,发现在进行本文一开始那种导出操作时,确实会出现占用内存激增的情况。

接下来解决问题,试了下用IO流导出,也会内存激增,不过导出文件相对小一些,所以占用内存也会小一些,但会导致导出文件失去可读性。所以就采用了让项目上调大启动命令的最大内存设置,优化导出逻辑(去除掉部分无用历史数据的导出),清掉了部分无用的历史数据使导出文件变小,从而解决问题。

以上。

你可能感兴趣的:(OOM,Java,heap,sp,Java)