首页 > 代码库 > 生成excel内存溢出问题的解决方式

生成excel内存溢出问题的解决方式

  常用的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内存溢出问题的解决方式