读取Excle内存溢出

前言

早上九点多,群里说生产上出现OOM,也定位到了出现异常的代码,读取Excle导致的,问了Excle里面有六万多条数据,生产上先加大了堆内存然后重启服务

问题确定

因为我们已经能大概确定问题代码了,但是我们还是想确认一下

登录服务器,首先要查找到对应的java进程

ps -ef|grep java

发现服务启动的参数类似下面的,生产设置的堆内存最大为512M

-Xms50m -Xmx50m -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=C:\Users\xxx\Desktop\temp

这就很舒服了,根据HeapDumpPath找到对应hprof,生成的hprof文件例如:java_pid9436.hprof,如果多个java进程的hprof文件都在一个目录下的话,要根据对应java进程的pid来获取到hprof文件

如果启动没有设置**-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\xxx\Desktop\temp**

因为这里已经能定位到问题,可以在本地上模拟出来,设置好启动的JVM参数就好了

这里借助MAT这一类的分析工具

在这里插入图片描述

可以看到有个超级大的对象占用了421.9M的内存

点击Dominator Tree 看看是谁占用

在这里插入图片描述

再根据前面已经定位到了出问题的代码,可以说明是由于解析数据量过多的Excle文件导致的此次OOM

本地重现

搞了个1万条数据的Excle,用读取Excle的问题代码直接读取,启动之前设置好JVM的参数

在这里插入图片描述

经过多次测试发现,堆内存要设置在500M以上,才能避免OOM,真的很吃惊,一万的数据量,竟然要花费至少512M的堆内存

具体原因

上网搜了一些资料,找到了问题所在

POI读取Excel有两种模式,一种是用户模式,一种是SAX事件驱动模式,将xlsx格式的文档转换成CSV格式后进行读取。用户模式API接口丰富,使用POI的API可以很容易读取Excel,但用户模式消耗的内存很大,当遇到很大sheet、大数据网格,假空行、公式等问题时,很容易导致内存溢出。POI官方推荐解决内存溢出的方式使用CVS格式解析,即SAX事件驱动模式

debug进去读取问题代码的Excle里去,发现使用的是UserModel

问题解决

  1. 可以自己写代码用SAX事件驱动模式处理
  2. 找一个比较好的开源(这里推荐alibaba的easyexcle)

我这里就选择了easyexcl(https://github.com/alibaba/easyexcel)
选择之前做了一下测试,直接在IDE上拉取代码,easyexcl仓库里面已经介绍了如何使用,这里我就不介绍了,直接测试,与前面的本地重现一下,设置好JVM,用的也是之前的Excle文件,经过多次测试,发现用至少用50M的堆内存,
在这里插入图片描述
发现使用的是SAX事件驱动模式处理的

处理

  1. 线上暂时加大堆内存
  2. 后期对处理Excle的代码进行优化,引入alibaba的easyexcle

总结

  • dump快照 工具分析
  • 定位到原因
  • 提出解决方案
  • 分析和验证解决
  • 找到最合适的处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值