还有充足的内存(Xmx为94GB / 200GB)时出现java.lang.OutOfMemoryError错误

8
我正在尝试创建大型RDF/HDT文件,这意味着需要将大型文件读入内存等。由于服务器有516GB的内存,其中约510GB是空闲的,所以这并不是一个问题。
我正在使用rdfhdt库来创建文件,这很好地完成了工作。然而,对于一个特定的文件,我不断收到OutOfMemoryError错误,没有真正的原因。以下是堆栈跟踪:
 Exception in thread "main" java.lang.OutOfMemoryError
    at java.io.ByteArrayOutputStream.hugeCapacity(ByteArrayOutputStream.java:123)
    at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:117)
    at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)
    at org.rdfhdt.hdt.util.string.ByteStringUtil.append(ByteStringUtil.java:238)
    at org.rdfhdt.hdt.dictionary.impl.section.PFCDictionarySection.load(PFCDictionarySection.java:123)
    at org.rdfhdt.hdt.dictionary.impl.section.PFCDictionarySection.load(PFCDictionarySection.java:87)
    at org.rdfhdt.hdt.dictionary.impl.FourSectionDictionary.load(FourSectionDictionary.java:83)
    at org.rdfhdt.hdt.hdt.impl.HDTImpl.loadFromModifiableHDT(HDTImpl.java:441)
    at org.rdfhdt.hdt.hdt.writer.TripleWriterHDT.close(TripleWriterHDT.java:96)
    at dk.aau.cs.qweb.Main.makePredicateStores(Main.java:137)
    at dk.aau.cs.qweb.Main.main(Main.java:69)

我正在使用标记-Xmx200G运行Jar文件。奇怪的是,在查看'top'时,它显示VIRT为213G(如预期)。然而,每次RES上升到约94GB时,它就会崩溃,并出现上述错误,这让我觉得很奇怪,因为它应该还有超过100GB可用。我查看了this中的问题,因为问题似乎与我的类似,尽管规模不同。但是,使用-verbose:gc-XX:+PrintGCDetails并没有给我任何指示出错的原因,同时还有大约500G的交换空间可用。
也许最奇怪的是,我遇到问题的特定文件甚至不是最大的文件。作为比例,它有大约83M个三元组要写入,对于其他文件,多达200M个三元组都不是问题。我正在使用Java版本1.8.0_66和Ubuntu版本14.04.3 LTS。
所以我的问题是,有人能解释一下我做错了什么吗?对我来说,更大的文件没有问题,但这个文件有问题。如果您需要任何其他信息,请告诉我。

好奇(与之前删除的评论有关):如果将-Xmx300G(从200增加),程序是否会完成?在这种情况下,进程使用的最大内存是多少? - user2864740
1
很遗憾,我试过使用-Xmx500G甚至更高的内存限制,但它仍无法运行(我猜这个值已经太高了)。总共我尝试过给它200、250、300、400和500GB的堆空间。 - Chraebe
似乎字典大小在内存中超过了相应Java结构的最大容量。您应该在Github上打开一个问题。有趣的是,这个文件和其他正常工作的文件之间是否有明显的区别?也许是更大的文字、不同节点的数量等等? - UninformedUser
你尝试过HDT的C++实现吗? - UninformedUser
1个回答

7

由于Java的最大数组长度限制,ByteArrayOutputStream无法容纳超过2GB的数据。这是无论您当前拥有多少RAM或内存限制都是如此。这里是你正在遇到的代码

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();

您需要重写代码,不要尝试将那么多数据存储在单个数组中。

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