写入Excel文件时出现内存不足错误 - Java堆空间溢出

8
我有将近10万条记录的数据,并且我正在尝试使用Java代码将数据写入.xlsx文件,使用的是XSSFWorkbook。我能够从数据库中获取所有数据到一个ArrayList中。通过迭代ArryList,我逐个单元格地将数据写入.xlsx文件。
当它达到8000行时,Java代码会抛出Out of Memory Heap Space错误。我曾经在某处读到过SXSSFWorkbookXSSFWorkbook更轻巧,所以我尝试使用了SXSSFWorkbook。但仍然遇到同样的问题。
那么,我的工作簿或Java代码有什么问题吗?最初,当我有6万条记录数据时,我使用了.xls文件。相同的Java代码可以使用HSSFWorkbook生成.xls文件。
增加Java堆空间绝不是一个选项,因为我的数据将来会大大增加。
非常感谢任何帮助。
以下是我写入Excel数据的代码片段。
int rowNum = sheet.getLastRowNum();

Row lastRow = null ;

Cell cell = null;

ReportingHelperVo reportingHelperVo = null; 

for (ReportingVo reportingVo : reportingVos) {

rowNum++;

lastRow = sheet.createRow(rowNum);

reportingHelperVo = reportingVo.reportingHelperVo;

cell = lastRow.createCell(0);

cell.setCellValue(reportingHelperVo.getLocation());

cell.setCellStyle(style);

cell = lastRow.createCell(1);

cell.setCellValue(reportingHelperVo.getCity());

cell.setCellStyle(style);

cell = lastRow.createCell(2);

cell.setCellValue(reportingHelperVo.getCountry());

cell.setCellStyle(style);

}

@AndersR.Bystrup 十万(使用南亚数字系统) - Saggio
1
好的,那很棒 :) 但不要期望南亚以外的人知道它。 - sschrass
3
@SatelliteSD 我不是楼主,我自己也得去查一下 :) - Saggio
1
这里有用途的代码段会很有帮助... - posdef
如果您使用SXSSFWorkbook,JMV何时会抛出OOM? - Taky
@Taky 当我将数据写入Excel时,当控制器达到10000时,OOM..!! - Sanjay
9个回答

12

SXSSFWorkbook并不像轻量级,但是它有一个优点。

如果您将其声明为

SXSSFWorkbook workbook= new SXSSFWorkbook(200);

每写入200行工作簿,就会将内存刷新到磁盘空间,以便不会对堆空间造成负担。


6

XSSFWorkbook - 创建了一个对象,用于表示所有的Excel文档(类似于DOM)。

SXSSFWorkbook - 应该需要恒定的存储器。JVM何时会抛出OOM?你使用了什么类型的ResultSet?尝试使用FORWARD_ONLY来限制JDBC驱动程序从数据库检索的缓存数据。

顺便说一下,解决OutOfMemoryError最好的方法是分析堆转储。 使用-XX:+HeapDumpOnOutOfMemoryError参数和MAT来了解您的应用程序的工作方式。


我没有使用JDBC来检索数据。我正在使用Hibernate,并将数据提取到ArrayList中。我需要查看XX:+HeapDumpOnOutOfMemoryError参数和MAT以获得更好的理解。感谢您的建议。 - Sanjay
你确定你的应用程序在数据大小增长时不会抛出OOM吗?尝试研究http://docs.jboss.org/hibernate/orm/3.3/api/org/hibernate/Session.html#doWork(org.hibernate.jdbc.Work)以直接使用JDBC并调整FetchSize和ResultSetType。 - Taky
我相信随着数据量的增长,JVM会抛出OOM异常。这就是我想要优化代码的地方,以便JVM每次都有足够的空闲堆内存。感谢您提供的链接。我会尝试并检查我的代码。 - Sanjay

2

我正在逐个单元格地将数据写入.xlsx文件。当它达到8000行时,Java代码会抛出内存不足堆空间错误。

重复使用现有的Java对象,而不是在每次迭代中创建新的对象。

或者使用CSV文件代替Excel。


我在Excel中启用了与工作表中写入的数据相关的宏函数。因此,我不确定CSV文件是否支持宏。另一方面,我的客户希望得到一个Excel报告。 - Sanjay
请在下面的代码中循环并创建行。重复使用暂时保存值的Java对象。 - NimChimpsky

1
Workbook workBook = new SXSSFWorkbook();

您可以导出超过1万条(100000)记录。


不好意思,现在我有五万条记录。但是 SXSSFWorkbook 仍然不支持。在 15,000 条记录时就会出现 OOM 错误。 - Sanjay
如果您在循环中使用了autosize列或某些样式,请避免它们。它们也可能会导致问题。 - swamy
是的,我正在使用循环中单元格边框的样式。但是我无法避免它们.. :( "Autosize column"是什么?感谢您的建议。 - Sanjay
不要在循环中创建这个 HSSFCellStyle style = wb.createCellStyle(); 你可以在外部声明它们,然后将它们传递给相应的方法。 - swamy
对我来说,当我从 XSSFWorkbook 切换到 SXSSFWorkbook 时,它确实起作用了。 - liam xu

0

你好,使用最新的Apache POI JAR包,并使用SXSSF进行流式传输或下载

 SXSSFWorkbook workbook = new SXSSFWorkbook(100); 
            workbook.setCompressTempFiles(true);
            Sheet sh = workbook.createSheet();
            ((SXSSFSheet) sh).setRandomAccessWindowSize(100);

//编写你的逻辑

   response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment; 
       filename="+filename+".xlsx");
            workbook.write(response.getOutputStream());
            workbook.close();
            workbook.dispose();

0

当我的Excel表格达到3000行时,我遇到了同样的问题。在我的情况下,POI Excel生成中的主要内存相关问题出现在样式表中。以下是我从代码中删除的内容:

  1. 尝试在行级别上使用样式表设置。
  2. 如果您确实需要为每个单元格设置样式表,请避免为每个单元格设置边框。

0

我在将XSSFWorkbook写入文件时遇到了内存不足的问题。
上面的建议帮了很大的忙。
请参见http://poi.apache.org/components/spreadsheet/how-to.html#xssf_sax_api

  1. 将 XSSFWorkbook wb = new XSSFWorkbook(); 改为 SXSSFWorkbook wb = new SXSSFWorkbook(-1);
    将 SXSSFSheet sh = ... 改为 SXSSFSheet sh = ...
    将 XSSFRow 改为 SXSSFRow
    将 XSSFCell 改为 SXSSFCell

  2. 在 for 循环中,每100行使用 sh.flushRows(100);

  3. wb.write(out); 后添加 wb.dispose();


0
我很久以前也遇到过类似的问题,试图使用XLConnection将数据从R写入Excel文件。最终,我通过使用write.csv解决了这个问题,然后在Excel中打开并使用“文本分列”按钮。它非常快速和可靠。

0

从数据库中返回页面结果而不是一次性读取它们。


我正在以小块(5000条记录)从数据库中获取数据,然后将数据写入Excel,并再次获取另外的5000条记录并将其附加到现有的Excel中。但是,当它在写入15000条记录时,Java代码仍会抛出OOM错误。 - Sanjay
我的Apache Tomcat5.5堆大小为1024m。我尝试使用我期望的行数读取虚拟.xlsx文件。但它抛出了OOM。 - Sanjay
虚拟文件在磁盘上有多大? - codeghost
仅仅通过快速的谷歌搜索,人们抱怨在使用该框架处理大小仅为4-6MB且JVM为1GB的文件时出现相同的异常。看起来内存占用是一个普遍问题。可能的解决方案是手动构建一个带有宏的Excel工作簿,并像之前建议的那样将数据写入CSV文件,然后使用宏将CSV导入到工作簿中。您甚至可以编写一个宏来自动化导入过程。 - codeghost
我认为那会对我有所帮助。但是我知道如何将数据写入CSV文件。你能告诉我如何将CSV文件导入工作簿吗?非常感谢。 - Sanjay
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接