捕获OutOfMemoryError但没有堆大小增加

时间:2011-05-24 17:54:05

标签: java memory-management error-handling out-of-memory

我的Java代码包含一个方法(getPermutations),其处理需要大量内存(Complexity O(n!)),因此可能抛出OutOfMemoryError。 重要的代码是:

ArrayList<ArrayList<Station>> permutations = getPermutations(stations);

我不想在我的特定机器上增加堆内存大小,我也无法在其他机器上更改它。 我正在寻找的是这种错误的某种异常处理(我很清楚错误或一般的throwable不应该被捕获)。

所以我想对OutOfMemoryError做出反应,并提供足够的(图形)消息,并防止我的小程序崩溃。

SwingWorker是正确的方法,它应该如何使用,还是有更好的选择?

提前致谢: - )

6 个答案:

答案 0 :(得分:2)

正如您所指出的,您不应该在程序逻辑中包含对OutOfMemoryErrors的处理。 OutOfMemoryError将被解释为“您的程序需要的内存比JVM / OS为您提供的内存更多”。

我建议您考虑返回Iterator<ArrayList<Station>>而是懒惰地产生排列,即按需。 (正如您可能知道的那样,返回集合的 size 可以在不知道实际内容的情况下轻松计算。)

  

SwingWorker是正确的选择吗?

很可能没有。

答案 1 :(得分:1)

抓住OutOfMemoryError,虽然您最终可能会遇到无法修复的情况。

有关详细信息,请参阅此讨论:http://www.velocityreviews.com/forums/t149419-catch-outofmemory-exception.html

PS。你真的想要获得阵列中的所有排列吗?考虑aioobe的答案,它在代码的可用性方面要好得多。

答案 2 :(得分:1)

如果内存不足,则没有足够的堆空间来绘制窗口和显示消息。因此,抓住它对你没有帮助。至于显示有用的消息,我建议您使用另一个进程处理该进程的退出代码。

但为什么不开始避免内存不足错误?即使是小型机器也可以产生排列,你只需要牺牲运行时间。如何将中间结果保存到磁盘?如果您没有提供库(我假设是因为您想显示错误消息),为什么不将内部模型更改为完全基于磁盘?

答案 3 :(得分:1)

你真的没有记忆吗?如果您正在迭代地处理列表并在自己之后进行清理,可能。也许这只是一个不允许GC完成应该工作的情况,java不能免于内存泄漏。悬挂引用,全局/静态变量等都可以使对象在真正进行GC时保留在范围内。

运行一个探查器(很多可用于Eclipse)可能很有用,可以准确地查看占用大量内存的内容。

也许这会有助于小批量处理?在过去使用过财务数据后,我发现一次处理数百万条记录是很常见的。通常,处理这些情况的最佳方法是将处理分解为更小,更易于管理的块。

答案 4 :(得分:0)

您可以像其他任何例外情况一样抓住OutOfMemoryError,然后根据您的喜好报告。 SwingUtilities.invokeLater()是在对话框中报告错误的好方法。你不会有恢复问题 - 从OutOfMemoryError回来通常是无痛的(如果剩余的对象现在有资格被收集,当然)。

答案 5 :(得分:0)

我同意答案,建议你分阶段增加排列。然后,您可以随时在抛出OutOfMemoryError时恢复:

boolean memoryFlag = false;  // flag is always available
try {
  Permutations bigVar = ... // some initial value
  while (/* condition */) {
    // Output your permutations so far discovered
    bigVar = ... // calculate the next extended set of permutations
  }
}
catch (OutOfMemoryError ex) {
  // bigVar is now out of scope, so is garbage
  System.gc();
  memoryFlag = true;
}
// program tests memoryFlag to report if out of memory occurred

您的用户界面可以继续不间断地运行。这在以前的单线程应用程序中对我有用。使用多个线程时,您将面临无法捕获错误的风险,因为每个Thread都使用自己的处理程序运行,并且您可能无法控制某些Swing线程的范围。