Excle导出优化
Posted vole
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Excle导出优化相关的知识,希望对你有一定的参考价值。
搜索词条
1、idea报java.lang.OutOfMemoryError: Java heap space怎么解决?
2、java.lang.OutOfMemoryError: GC overhead limit exceeded怎么解决?
3、xssfworkbook导出Excel内存溢出?
4、如何查看jvm内存使用情况?
背景:使用POI导出海量数据内存溢出问题
应用配置:idea+tomcat7+informix+jdk7+poi3.9
本地机器的物理内存为8G,没有对JVM进行配置。
场景:从数据库查询大批量数据(其实就2万条数据),List存放2万条数据,利用poi,通过自己写的Excle数据导出工具,对数据进行处理,并以Excel文件的形
式进行导出(会创建1个或多个sheet页)。创建Excle调用的方法如下(Utils中有Excle上传及导出工具,此处不再粘贴代码):
XSSFWorkbook wb = new XSSFWorkbook();
在导出Excle文件时,出现下述异常:
异常一: 严重: Servlet.service() for servlet [springMVC] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause java.lang.OutOfMemoryError: Java heap space 在JVM中如果98%的时间是用于GC且可用的 Heap size 不足2%的时候将抛出此异常信息。JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置。 JVM在启动的时候会自动设置Heap size的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。如果Heap Size设置偏小,除了这些异常信息外,还会发现程序的响应速度变慢了。GC占用了更多的时间, 而应用分配到的执行时间较少。 Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。 Heap size的 -Xms -Xmn 设置不要超出物理内存的大小。否则会提示“Error occurred during initialization of VM Could not reserve enough space for object heap”。
当未对JVM进行配置时,出现异常一,原因如下:Excle工具采取poi框架对Excle进行导出导致的JVM内存溢出。原因是所创建的book sheet row cell 等,此时是存在内存的,并没有 持久化,那么随着数据量增大内存的需求量也就增大,那么很大可能就是要 OOM了。而我本地并未对JVM进行配置,均采用的默认配置。当导出2万条数据时,就导致了内存溢出。(测试了下,在准备金系统的开发环境也有该问题,测试环境与生产环境还未出现OOM问题(内存足够))。
然后我对JVM进行了配置(下面会对JVM的调优进行详细说明):
-Xms512m -Xmx2048m -Xss1024K
在进行导出时,出现了异常二:
java.lang.OutOfMemoryError: GC overhead limit exceeded 出现该错误的原因是因为垃圾回收为了释放较小的空间而占用了大量时间造成的。通常来说,当程序用98%的时间回收了不到2%的堆内存时导致的。通常是设置的堆内存太小,导致没有足够的内存。 解决方法
1、首先检查程序有没有死循环或者其他一些导致内存被大量占用的程序,如果确定程序没有问题,只是程序本身需要大内存时,通过设置增加内存。 2、添加jvm启动参数限制使用内存:-XX:UseGCOverheadLimit 方法:找到tomcat部署路径下./bin/catalina.sh文件,打开,并在cygwin=false这一行的上面添加(分两种情况) 1> 在java1.8之前的版本中 JAVA_OPTS="-Xms512m -Xmx2048m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:-UseGCOverheadLimit" 2> java1.8版本 JAVA_OPTS="-Xmx12000m -XX:-UseGCOverheadLimit" 这是一种应付了事的解决方案, 就是不想抛出 “java.lang.OutOfMemoryError: GC overhead limit exceeded” 错误信息, 添加下面启动参数: // 不推荐 -XX:-UseGCOverheadLimit 我们强烈建议不要指定该选项: 因为这不能真正地解决问题,只能推迟一点 out of memory 错误发生的时间,到最后还得进行其他处理。指定这个选项, 会将原来的 java.lang.OutOfMemoryError: GC overhead limit exceeded 错误掩盖,变成更常见的 java.lang.OutOfMemoryError: Java heap space 错误消息。 需要注意: 有时候触发 GC overhead limit 错误的原因, 是因为分配给JVM的堆内存不足。这种情况下只需要增加堆内存大小即可。 在大多数情况下, 增加堆内存并不能解决问题。例如程序中存在内存泄漏, 增加堆内存只能推迟产生 java.lang.OutOfMemoryError: Java heap space 错误的时间。 当然, 增大堆内存, 还有可能会增加 GC pauses 的时间, 从而影响程序的 吞吐量或延迟。 如果想从根本上解决问题, 则需要排查内存分配相关的代码. 简单来说, 需要回答以下问题: 哪类对象占用了最多内存? 这些对象是在哪部分代码中分配的。 要搞清这一点, 可能需要好几天时间。下面是大致的流程: 获得在生产服务器上执行堆转储(heap dump)的权限。“转储”(Dump)是堆内存的快照, 可用于后续的内存分析. 这些快照中可能含有机密信息, 例如密码、信用卡账号等, 所以有时候, 由于企业的安全限制, 要获得生产环境的堆转储并不容易。 在适当的时间执行堆转储。一般来说,内存分析需要比对多个堆转储文件, 假如获取的时机不对, 那就可能是一个“废”的快照. 另外, 每执行一次堆转储, 就会对JVM进行一次“冻结”, 所以生产环境中,不能执行太多的Dump操作,否则系统缓慢或者卡死,你的麻烦就大了。 用另一台机器来加载Dump文件。如果出问题的JVM内存是8GB, 那么分析 Heap Dump 的机器内存一般需要大于 8GB. 然后打开转储分析软件(我们推荐Eclipse MAT , 当然你也可以使用其他工具)。 检测快照中占用内存最大的 GC roots。详情请参考: Solving OutOfMemoryError (part 6) – Dump is not a waste。 这对新手来说可能有点困难, 但这也会加深你对堆内存结构以及 navigation 机制的理解。 接下来, 找出可能会分配大量对象的代码. 如果对整个系统非常熟悉, 可能很快就能定位问题。运气不好的话,就只有加班加点来进行排查了。 参看链接:有详细说明:https://blog.csdn.net/renfufei/article/details/77585294
我进行了下述配置(下面会对如何对服务进行JVM配置进行详细说明):
-Xms512m -Xmx2048m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:-UseGCOverheadLimit
虽然偶尔可以导出成功,但确实,大多数情况下报异常一。这也证实了上述所述的原因。
我通过java自带的jconcole工具查看了当进行导出时,JVM占用内存的变化情况,如下图:15:00之前是当数据量在1万条左右时,多次导出,堆内存使用量在1G
浮动,但仍可以正常进行导出。15:00以后是当导出的数据条数达到2万后,当第一次启动服务,并导出时,可能会导出成功一次,往后均OOM。15:30是一段时
间没进行导出操作后,对内存使用量才降下来的。(下面会详细说明怎么查看JVM的内存使用量)
通过上述分析,可以得出结论,导致内存溢出的原因,就是poi的Excel导出工具占用的内存太大。解决方案如下:
两种方案:
第一种:当数据量并不是特别大的时候,可以通过设置JVM的内存,导出大批量的数据。但是当数据量达到百万后,只有通过方案二来解决。
第二种:通过SXSSFWorkbook来导出。
(TODO:关于poi导出Excel文件的详细说明)
XSSFWorkbook wb = new XSSFWorkbook();
延伸
1、频繁full gc有什么影响?
2、JVM 内置的通用垃圾回收原则。
3、配置JVM的内存。
4、JVM调化。
5、导致OOM的三种可能原因
6、如何查看JVM的内存
7、如何配配置JVM的内存
以上是关于Excle导出优化的主要内容,如果未能解决你的问题,请参考以下文章