HA

记一次OOM异常解决

问题描述

一台服务器出现OOM(为本应用分配了4G内存),挂掉了

java.lang.OutOfMemoryError: GC overhead limit exceeded

问题排查

拿到dump文件,使用jvisualvm打开查看后,发现下面两个对象实例数,占用空间过高

类名 实例数百分比 实例数 大小
org.apache.xmlbeans.impl.store.Xobj$AttrXobj 40% 1500w 2G
org.apache.xmlbeans.impl.store.Xobj$ElementXobj 12% 450w 700M

问题分析

查代码发现疑似是使用poi解析excel文件时解析文件占用过多内存,解析文件的时候会解析整个文件,解析excel其实就是在解析xml,非常的消耗内存

问题解决

调查发现可以使用流式读取一次只读取特定的行数,降低内存占用

测试验证,未修改前,设置jvm内存为500M,解析1M以上的excel文件就会报OOM,修改后,问题未出现

解决方案

使用这位仁兄写成的包装库,因为不想升级项目poi的版本,影响太大,同时又想用到原来的Workbook里面的一些api,所以选择了1.0.2版本,这版的poi依赖版本依然高于我们项目中的poi,于是只好把fork一份之后降低poi版本后重新编译一个包出来用

reference