java.lang.OutOfMemoryError:从txt文件读取并写入xlsx文件时的Java堆空间

时间:2011-12-06 15:32:40

标签: java memory

我正在编程以创建一个工具来将可编译的.txt文件转换为可读的.x​​lsx文件。 (我需要使用xlsx,因为我正在处理超过256个列,所以我在编写行和列时使用XSSFWorkbook)。

编码部分没问题。我知道这是因为我多次验证它但是当我尝试在代码中添加新的编码地图时,它们都以:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.io.ByteArrayOutputStream.write(Unknown Source)
    at org.apache.poi.openxml4j.opc.internal.MemoryPackagePartOutputStream.write(MemoryPackagePart OutputStream.java:88)
at org.apache.xmlbeans.impl.store.Cursor._save(Cursor.java:590)
at org.apache.xmlbeans.impl.store.Cursor.save(Cursor.java:2544)
at org.apache.xmlbeans.impl.values.XmlObjectBase.save(XmlObjectBase.java:212)
at org.apache.poi.xssf.usermodel.XSSFSheet.write(XSSFSheet.java:2480)
at org.apache.poi.xssf.usermodel.XSSFSheet.commit(XSSFSheet.java:2439)
at org.apache.poi.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:196)
at org.apache.poi.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:200)
at org.apache.poi.POIXMLDocument.write(POIXMLDocument.java:204)
at model.Conversione.traduzioneFile(Conversione.java:241)
at model.Main.scriviFile(Main.java:76)
at model.Main.main(Main.java:52)

错误发生在3000/4000行之后,内存就像这样 起始值:

14443720 的 * * :13572128 的 * * :12078128 的 * * :10575592 * * :14126224 - >新增量始终低于起始值然后减少 的 * * :12559920 的 * * :11811440 的 * * :10229128 * * :13751400 - > ... 的 * * :13011080

“编码地图”通常是HashMap<Integer,Hashmap<Integer,String>>类型的地图。 (我这样做是因为我不能使用数据库..)

所以程序主要是:

- 首先实例化并创建整个地图, - .txt文件的读线, -split the line,获取一个令牌,使用地图翻译它并将其放入行和列中 -wb.write(fileOutputStream fos) -fos.close。

即使在翻译操作中没有考虑我添加的地图,我也无法理解为什么会出现错误......

为什么内存数量如此可变? (但永远不会回到起点?)

如果我在某些方面不清楚,请问..我不知道该怎么做..

一开始我认为这是一个缓冲问题,因为.xlsx文件的大小越来越大(即使......我说过......因为没有使用新的地图,所以应该没有改变。)

任何暗示赞赏..

露西亚

5 个答案:

答案 0 :(得分:1)

您可以使用jvisualvm或jmap -histo来检查占用内存的内容:live。如果应用程序确实需要内存,您可以尝试增加内存限制-Xmx ...

答案 1 :(得分:1)

如果您在运行独立Java应用程序时在eclipse中遇到此问题。右键单击您的java progrram,单击“运行为 - &gt;运行配置”。单击参数选项卡,然后在VM参数字段中键入-Xms1024M -Xmx1024M。从eclispe运行时,这会增加VM大小。

答案 2 :(得分:0)

默认情况下,Eclipse将分配最多384 MB的Java堆内存。这应该适用于所有典型的开发任务。但是,根据您运行的JRE,您正在使用的其他插件的数量以及您将使用的文件数量,您可以想象必须增加此数量。 Eclipse允许您使用-vmargs命令行参数将参数直接传递给Java VM,该参数必须遵循所有其他Eclipse特定参数。因此,要增加可用堆内存,通常使用:

eclipse -vmargs -Xmx<memory size>

将值设置为大于“384M”(384兆字节 - 默认值)。

使用Oracle(Sun)VM时,您可能还需要增加永久代内存的大小。默认最大值为64 MB,但根据您的插件配置和使用情况,可能需要更多。当VM耗尽永久生成内存时,它可能会在类加载期间崩溃或挂起。使用Sun JRE 1.5.0_07或更高版本时,此故障不太常见。使用-XX:MaxPermSize =参数:

增加最大永久生成大小
**eclipse -vmargs -XX:MaxPermSize=<memory size>**

答案 3 :(得分:0)

这与缓冲无关。由于堆中有太多对象和/或最大内存的-Xmx设置太低,因此内存不足。您可以在与测试/实用程序对应的Arguments选项卡中的Eclipse中的“Run Configurations”中增加-Xmx。您可以在VM Arguments块中添加-Xmx 512M(或左右)。

但真正的问题是你试图在内存中同时存储太多对象。我不确定我理解HashMap HashMap的{​​{1}}。如果文本文件中每行有HashMap,则会占用大量内存。 @ AKJ的答案提供了一些工具来诊断哪些对象占用的空间最多。 VisualVM是一个很好的起点。

答案 4 :(得分:0)

我建议您使用SXSSFWorkbook(需要Apache POI&gt; = 3.8 beta 3)而不是XSSFWorkbook,因为它建议here

final SXSSFWorkbook workbook = new SXSSFWorkbook(20);

创建一个工作簿,其行访问窗口大小为20,即最多只有20行保存在内存中,其余的在磁盘上刷新。

在执行此操作时需要注意一些缺陷,如果需要调用SXSSFSheet.autoSizeColumn,请避免将空值放入单元格并尽快调用SXSSFSheet.trackAllColumnsForAutoSizing()(需要Apache POI&gt; = 3.15) (int)稍后自动计算列的大小。