常用的excel生成工具包括jxl、poi。但二者都存在一个问题:生成excel需要大量的消耗内存。如果一次性往excel中写入的数据足够的多将导致内存溢出。

1、数据写入excel为什么会大量的消耗内存?

  这需要从excel特点以及jxl和poi的实现原理来分析。excel即表格,一个一个的单元格。我们生成excel就是往一个个的单元格里面写数据。如下代码(使用的jxl):

WritableWorkbook wwb = Workbook.createWorkbook(new File(fileName));
            WritableSheet ws = wwb.createSheet(wjmc, 0);
            WritableFont wfont = new jxl.write.WritableFont(
                        WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false,
                        UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.BLACK);
            jxl.write.WritableCellFormat normalStyle = new jxl.write.WritableCellFormat(wfont);
            normalStyle.setLocked(true);// 保护单元格
            /**写入文件表头 begin */
            Label labelC = null;
            labelC = new Label(0, 0, "零件名称");
            ws.addCell(labelC);
            labelC = new Label(1, 0, "精友零件编码");
            ws.addCell(labelC);
            StringBuffer sycxString=null;
            if (rs != null) {
                int j = 1;
                while (rs.next()) {
                    String id = rs.getString("id");

                    sycxList = getSycxList(id);
                    sycxString = new StringBuffer();
                    if (sycxList != null) {
                        for (Iterator it = sycxList.iterator(); it.hasNext();) {
                            sycxString.append((String) it.next()).append("\n");
                        }
                    }
                    String commonPart=rs.getString("sec_id") == null?"否":"是";
                    labelC = new Label(0, j, rs.getString("ljmc"), normalStyle);
                    ws.addCell(labelC);
                    labelC = new Label(1, j, rs.getString("ljbm"), normalStyle);
                    ws.addCell(labelC);
                    j++;
                }

  这是一段典型的excel生成代码。这样的逻辑在数据量小的时候没有问题。但一旦数据量大,如红色标注的那一行:每一个单元格都需要new一个对象。最重要的,这些对象被excel对象WritableSheet所引用,在excel整个生成完成前无法被回收。内存就这样被占据消耗了!如果多用户同时并发导出excel.....显然jvm内存溢出是必然的!

2、如何避免内存溢出?

  上面分析的内存溢出的主要原因是当数据量大的时候,开辟的内存空间一直被占据着不释放。如果能缩短被占据的时间,内存就能及时被释放。从而避免内存溢出!要缩短被占据的时间,就要减少写入一个excel中的数据量。让单个的excel短时间内就能完全生成。即将大量的数据分批次写入到多个excel中!这样当一个excel生成完成之后,它所引用的单元格对象就能被回收释放。

  poi3.8版本之后引入了一种全新的解决此类内存溢出的方法。如下代码:

Workbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
 Sheet sh = wb.createSheet();
 for(int rownum = 0; rownum < 100000; rownum++){
 Row row = sh.createRow(rownum);
 for(int cellnum = 0; cellnum < 10; cellnum++){
 Cell cell = row.createCell(cellnum);
 String address = new CellReference(cell).formatAsString();
 cell.setCellValue(address); }
 }
FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
 wb.write(out);
 out.close(); 

  在生成excel对象的时候可以指定其在内存中保留的数据量。超出指定数据量的数据后,会将之前的数据转到硬盘上。(注:此种方法是否有效个人尚未验证过)这样就避免了所有的单元格数据都保留在内存中,占据着不释放!

生成excel内存溢出问题的解决方式的更多相关文章

  1. Spark Shuffle 堆外内存溢出问题与解决(Shuffle通信原理)

    Spark Shuffle 堆外内存溢出问题与解决(Shuffle通信原理) http://xiguada.org/spark-shuffle-direct-buffer-oom/ 问题描述 Spar ...

  2. Java虚拟机系列(三)---内存溢出情况及解决方法

    因为Java虚拟机内存有堆内存.方法区.虚拟机栈.本地方法栈和程序计数器五部分组成,其中程序计数器是唯一一块不会发生内存溢出异常的内存区,所以只有四类内存区可能发生内存溢出异常,其中虚拟机栈和本地方法 ...

  3. Tomcat常见的内存溢出,以及解决方法

    一.常见的三种内存溢出错误: 1.java.lang.OutOfMemoryError:java heap space    ====JVM Heap(堆)溢出 JVM再启动的时候回自动设置JVM H ...

  4. C++中避免内存泄露常见的解决方式

    常见内存泄露及解决方式-选自ood启发录 new/delete, array new/arrray delete匹配 case 1: 在类的构造函数与析构函数中没有匹配地调用 new/delete! ...

  5. java内存溢出的情况解决方法

    内存溢出虽然很棘手,但也有相应的解决办法,可以按照从易到难,一步步的解决. 第一步,就是修改JVM启动参数,直接增加内存.这一点看上去似乎很简单,但很容易被忽略.JVM默认可以使用的内存为64M,To ...

  6. jmeter(二十二)内存溢出原因及解决方法

    jmeter是一个java开发的开源性能测试工具,在性能测试中可支持模拟并发压测,但有时候当模拟并发请求较大或者脚本运行时间较长时,压力机会出现卡顿甚至报异常————内存溢出, 这里就介绍下如何解决内 ...

  7. <转>jmeter(二十二)内存溢出原因及解决方法

    本博客转载自:http://www.cnblogs.com/imyalost/category/846346.html 个人感觉不错,对jmeter讲解非常详细,担心以后找不到了,所以转发出来,留着慢 ...

  8. [转]JVM内存溢出的几种方式比较

    转载自:https://github.com/pzxwhc/MineKnowContainer/issues/25 包括: 1. 栈溢出(StackOverflowError) 2. 堆溢出(OutO ...

  9. jmeter 内存溢出原因及解决方法

    jmeter是一个java开发的开源性能测试工具,在性能测试中可支持模拟并发压测,但有时候当模拟并发请求较大或者脚本运行时间较长时,压力机会出现卡顿甚至报异常————内存溢出, 这里就介绍下如何解决内 ...

随机推荐

  1. UVA 140 (13.07.29)

     Bandwidth  Given a graph (V,E) where V is a set of nodes and E is a set of arcsin VxV, and anorderi ...

  2. LeetCode——Valid Palindrome

    Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...

  3. Spring AOP 实现原理与 CGLIB 应用--转

    AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 ...

  4. noip 2012 开车旅行

    /*考场上写的暴力 40分钟70分*/ #include<iostream> #include<cstdio> #include<cstring> #define ...

  5. sourceTree添加git密钥步骤

    给多个远程服务器比如https://github.com/wangjian2014/wjtest/blob/master/wj.txt添加public密钥 本地服务器添加private密钥     S ...

  6. (转)SQL流程控制语句学习(一):变量及控制语句种类

    1.局部变量 用户自己定义的,称局部变量,以@标识. 作用范围:定义局部变量的批处理.存储过程.触发器和语句块 局部变量的定义: declare @局部变量名 数据类型 注意:变量的类型不能是text ...

  7. PHP Socket编程起步

    让我们以一个简单的例子开始---一个接收输入字符串,处理并返回这个字符串到客户端的TCP服务.下面是相应的代码: PHP 代码: ) or die("Could not read input ...

  8. geotools导入shp文件到Oracle数据库时表名带下划线的问题解决

    问题: 最近在做利用geotools导入shp文件到Oracle表中,发现一个问题Oracle表名带下划线时导入失败,问题代码行: dsOracle.getFeatureWriterAppend(or ...

  9. epoll模型的et模式和lt模式

    http://www.cppblog.com/peakflys/archive/2012/08/26/188344.html    评论区讨论,唐诗! http://www.cnblogs.com/e ...

  10. js中的|| 与 &&

    a && b : 将a, b转换为Boolean类型, 再执行逻辑与, true返回b, false返回aa || b : 将a, b转换为Boolean类型, 再执行逻辑或, tru ...