【问题标题】:Java: Garbage CollectionJava:垃圾收集
【发布时间】:2010-12-13 02:53:51
【问题描述】:

我遇到了内存不足错误。我有很大范围的输入(2^40),太大而无法一次保存。每个输入都是一个String[]

相反,我认为我会在每个输入上运行我的测试程序,将结果写入文件,然后丢弃输入。最长输入的length 是42,所以这不是导致溢出的错误。我不认为我了解垃圾收集。

PowerSet 就像一个惰性列表 - 在调用 .next() 之前不会计算结果。每个结果返回baseSet 的一个子集。 baseSet 是一个长度为 40 的 String[]。 runTests 对输入进行一些分析并将其写入文件。

PowerSet argSetSet = powerset(baseSet); 
while (argSetSet.hasNext()) {
    runTests(argSetSet.next()); //saves output to file
}

这会导致内存不足错误。但是我没有将 argSetSet.next() 的结果保存在任何地方,那么为什么会发生这种情况呢?我不需要存储来自next()runTests() 的任何数据。如何确保所有内容都被垃圾回收?

如果我注释掉runTests(),它运行良好。

【问题讨论】:

  • 确切的错误信息是什么?是OutOfMemoryError,表示对象太多?或者*Error,这表明存在递归错误?

标签: java memory-management garbage-collection heap-memory


【解决方案1】:

[类似于 Clippy 的图标] 看来您正在计算一个非常大的集合的幂集。你想增加你的堆大小吗?

我担心的是你说这是一个惰性列表,这意味着整个 powerset 实际上并不在内存中,而是在你调用 .next() 时只有一部分在内存中。但是,根据 .next() 实际返回的内容(数组的大小),默认堆大小很可能不够。

您可以通过指定 -Xmx1024m 来增加堆的大小(将堆的最大值设置为 1gb)。显然,您可以调整该大小,但这将允许您测试它是否可以缩放。这不是一个最终的解决方案,但它至少应该给你一些跑道。

【讨论】:

  • next() 返回的数组的最大大小为 40。
  • 好吧,那肯定是关闭了。我建议下载像 yourkit (yourkit.com) 这样的分析器并试用他们的 Java Profiler。你可以看到内存被保存在哪里。从您的 cmets 来看,您在 runTests 的内存中保留了数组或字符串的值。不确定您是否想向我们公开该方法,但请查找您将其放入地图/列表/集合中的位置并且不清除地图或使用静态集合。
【解决方案2】:

附加一个像 jvisualvm 这样的分析器并调查你的记忆去向。你可能会感到惊讶:)

【讨论】:

    【解决方案3】:

    您没有将.next() 的结果存储在任何地方这一事实并不相关,相关的是 .next() 实际在做什么。

    您是否将堆大小设置为非默认大小?您使用什么设置来启动 JVM? JVM 的默认堆大小只有 64M,因此one trillion 条目肯定无法放入该空间。

    【讨论】:

      【解决方案4】:

      baseSet 中有什么?我猜这会占用大量内存。当 PowerSet 在内部使用 baseSet 时,这可能会加剧。

      【讨论】:

        【解决方案5】:

        没有足够的代码来理解发生了什么,主要是 PowerSet,但 PowerSet 必须计算 String 数组以返回下一个方法。可能是它正在抓住那个物体。

        内存问题出在 runTests 方法或 PowerSet 类中。它不在您发布的代码中。

        【讨论】: