记一次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内部代码位置,如下:

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

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

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

然而同事使用 IBM HeapAnalyzer打开快照文件后, 发现其中有一个 1.7G的大数组!! 至于为什么两个工具分析的结果不同,目前也不知道原因(还是推荐使用MAT https://www.ibm.com/support/pages/ibm-heapanalyzer)。不过通过这个大数组和前面报错代码位置,基本可以确定就是在数组扩容时内存溢出了。

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

接下来解决问题,试了下用IO流导出,也会内存激增,不过导出文件相对小一些,所以占用内存也会小一些,但会导致导出文件失去可读性。分析客户的导入文件,发现其中大部分信息是不必要信息,所以优化导出逻辑,去除掉部分无用历史数据的导出,使导出文件变小,从而解决导入时的OOM问题(也可通过调大MaxHeapSize解决)。

以上。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值