2012-12-28 61 views
1

我正在读取大小为2.6GB的单个XML文件--JVM的大小为6GB。获取堆空间内存不足错误 - 如何使用java堆内存

但是我仍然遇到堆空间不足的内存错误?

什么我错在这里做什么......

仅供参考,我输出的最大内存被显示为约5.6GB的JVM--

最大内存和可用存储性能,但免费内存显示为只有90MB ...为什么只有90MB显示为空闲,尤其是,当我还没有开始任何处理...我刚开始该程序?

+1

你正在使用什么操作系统?有些人限制一个进程可以消耗多少内存......我相信32位Windows是最大2GB。 –

+4

2.6GB XML - OMG!使用数据库!由于所有节点对象,子列表,属性对象等,将XML文件存储在内存中将比磁盘上的平面文件占用更多的空间。 – jlordo

+0

@jlordo - 使用SAX或DOM读取XML文件可以是完全适合的事情要做。根据需求,数据库实际上可能是最糟糕的可能解决方案。恕我直言... – paulsm4

回答

8

通常,在将结构化文本转换为Java中相应的数据结构时,需要比输入文件的大小多。除了字符串所需的空间之外,还有很多与所使用的各种数据结构相关的开销。

例如,每个String实例具有约32-40字节的附加开销 - 更不用说每个字符被存储在字节,这有效地加倍了ASCII编码的XML的空间要求。

然后,当将字符串存储在结构中时,您有额外的开销。例如,为了在Map中存储String实例,您将需要大约16-32字节的额外开销,具体取决于实现以及如何衡量使用情况。

这很可能是6GB是不足够存储一部2.6GB解析XML文件在一次...

底线:

如果您在加载这么大的XML文件内存(例如使用DOM解析器),你可能做错了什么。基于流的解析器(如SAX)应该具有更为适中的要求。

或者考虑将XML文件转换为更可用的文件格式,例如嵌入式数据库 - 甚至是实际的基于服务器的数据库。这将允许您处理更大的文档而没有问题。

+0

+1每个字节至少变成一个16位字符,每个字符串都是该文件的每个部分都有大约32字节的开销。 –

+0

[这里是一个例子](http://www.mathworks.com/matlabcentral/newsreader/view_thread/296735)在Java中读取时,5MB XML文件使用60MB内存。 – jlordo

+0

“6GB很可能不足以一次性存储解析的2.6GB XML文件”。真正。但重点是1)确保*你正在运行一个64位的JVM(一个可以使用2GB以上!),2)使用VisualVM(nee JConsole)这样的工具准确分析正在使用多少内存,以及它要去的地方。恕我直言... – paulsm4

1

您应该避免一次加载整个xml到内存中,而是使用可以处理大量xml的专用类。

+1

绝对的。具体而言,基于* SAX *的类只读取XML中即时感兴趣的部分。 – paulsm4

1

这里可能有几个不同的问题。

但对于初学者:

1)如果你使用的是64位操作系统,让你使用确保 64位JVM

2)确保您的代码将关闭所有尽可能及时地打开资源。

3)显式设置大对象的引用为“null”。

... AND ...

4)JConsoleVisualVM熟悉:

+0

通常,如果指定了过大的堆大小,JVM将拒绝启动,例如,如果没有足够的物理内存可用或使用32位JVM并且请求的内存太多。我假设如果OP设法用'-Xmx6144m'启动JVM,那么他们实际上使用的是64位操作系统和JVM ...... – thkala

1

不能装载2.6 GB的XML图像的文件只有6 GB。正如jhordo所建议的那样,该比率更可能是12比1.这是因为每个字节都变成了16位字符,每个标签,属性和值都变成了一个至少有32字节开销的字符串。

相反,你应该做的是使用SAX或基于事件的解析器来逐步处理文件。这样它将只保留尽可能多的数据,因为你需要保留。如果您可以一次处理所有内容,则不需要保留任何内容。