最近手里维护公司一个旧项目,导出excel的时候偶尔会OOM,堆内存溢出。通过本地重现,使用jvisualVM工具分析堆空间后发现,某个实例数所占用极高,上传5M的文件竟然产生了近100M的该实例,听说poi吃内存,但实际分析下来还是蛮惊讶的。
而网上关于excel导出OOM的方案有很多种,包括apache对poi的写改进,然而这个不是我们想要的,最终采用的是ali的easyExcel。为啥使用easyExcel能解决OOM呢,原来我们一次性加载到内存的excel数据,虽然不大,但是一次性读取那么多行和列,实际上没有必要,我们可以采取分批次读取,然后清空之前的读缓存来实现内存的最大化利用,这样读再大的文件也不用害怕了,只是读取的批次多一点,时间处理长一点罢了。
以下是我本地进行测试对比的过程,为了更好的显示出效果,我设置了此次进程的最大堆使用时168M,idea的启动配置如下。(为啥是168M大家可以思考以下,后面JVM分析工具里也可以看得出)
上面配置了HeapDumpPath是在OOM后将堆栈信息输出到后缀为hprof的文件中,而VisualVM工具为我们提供了该格式文件的读取分析。
ok,运行,然后点击下载,同时打开我们的VisualVM工具,实时分析下载过程的内存占用,因为我事先控制了堆大小,所以此次试验用poi方式导出是一定能看到OOM的,接下来我们就观察这个过程吧。
在我点完postman后,old区很快就满了,后面我们发现GC的频率已经跟不上产生对象的速度了,98%的时间在GC而可用空间一直不到2%,最终OOM,我们也得到了堆日志hprof文件
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/java_pid39344.hprof ...
Heap dump file created [284891634 bytes in 1.294 secs]
去D盘找到该文件 导入到VisualVM里进行分析。如下所示
很明显发现前两个实例分别是apache.xmlbeans.impl.store下的Xobj实例,这么多实例数用了多大内存呢?
额,接近100M,而我们上传的文件只是5M大小的excel。可以说非常吃内存了。
下面看看EasyExcel的表现怎么样。
开始之前,注意到
EasyExcel · 语雀www.yuque.com里有句话:
64M内存1分钟内读取75M(46W行25列)的Excel
可以说很牛了。根据上面的条件,我上传的文件是5M,堆内存是168M,easyExcel应该可以轻松应对。
再看下核心代码,除了dao层的代码会与官方demo不一样,其他都可以照搬。
通过对比,很容易看出easyExcel的性能更优。
-------------------------- 我是分割线 -------------------------------
欢迎加我微信交流
https://u.wechat.com/EE_j6UlJrr2mIcyMqpI1aAc (二维码自动识别)