捕获OutOfMemoryError

是否有任何一点在Java中捕获内存不足错误( java.lang.OutOfMemoryError )?

是的 以下是一些有意义的例子:

  • 如果你想通过优雅地关闭你的程序来处理它
  • 如果要向用户显示问题或记录错误
  • 根据您的设计,您甚至可以清理内存并恢复工作状态

但是 ,请注意通常情况下(除非你在某个地方同时分配大量内存),你可能不会特别针对这些情况捕获OutOfMemoryError,而是在顶部catch Throwable在您的主要入口点。

黄金法则是只捕获您可以处理的错误。 如果您在OutOfMemory错误后可以执行一些有用的操作,那么请继续。

不,捕获ExceptionRuntimeException ,但几乎没有(从’never’更改) Error

Error是Throwable的子类,表示合理的应用程序不应该尝试捕获的严重问题。 大多数此类错误都是exception情况。 ThreadDeath错误,虽然是“正常”条件,但也是Error的子类,因为大多数应用程序不应该尝试捕获它。

注意:
我在这里引用官方的Javadocs。 如果你不同意,告诉甲骨文,不要拍信使:-)

正如其他一些答案所指出的,捕获OutOfMemoryError并尝试恢复1是一个坏主意 。 而不是仅仅重复javadoc说你Errorexception是不可恢复的,我会试着解释原因。

事实上,至少有两个可靠的理由为什么OOME恢复是不明智的:


第一个原因是OOME 通常是未确诊的内存泄漏的结果。 如果您的应用程序捕获并尝试恢复,则泄漏的内存仍然可以访问,因此仍然无法回收。 因此,当您的应用程序开始执行操作时,可能会泄漏更多内存…并遇到另一个OOME。 应用程序迟早会停止运行。

由于无法确定您的应用程序不会泄漏,因此OOME恢复永远不会是一个可靠,可靠的答案。


第二个原因是当OOME发生时,它可能会对执行状态造成损害。 它可能导致线程终止,让其他线程等待永远不会到达的通知等。它可能发生在更新关键应用程序数据结构或(可能更糟)JVM数据结构的过程中。 如果您的应用程序然后尝试恢复,它可能会锁定,或者(更糟糕的是)它可能会继续使用损坏的数据,并产生不可预测的结果。

除非您对代码库进行取证分析,否则您永远不能完全确定不会发生这种情况。


我不会说你永远不应该尝试从OOME中恢复,但总的来说这是一件冒险的事情。 而且您的应用程序越复杂,评估风险就越困难。


1 – 我在这里谈论捕获OOME以试图让应用程序像以前一样继续运行; 即恢复申请。 捕获OOME以执行(或触发)有序关闭是另一回事。

如果你想要一个优雅的关闭特定处理这种情况。

如果您可能需要分配大型arrays并且希望优雅地降级系统,也可以使用它。

编辑:代码的一个例子,我曾经检查过OOM流是否已损坏。 我已经替换了len检查以确保len在0到16 MB之间。

 DataInputStream dis = new DataInputStream(socket.getInputStream()); public byte[] readBytes() { int len = dis.readInt(); try { byte[] bytes = new byte[len]; dis.readFully(bytes); return bytes; } catch(OutOfMemoryError e) { log.error("Corrupt stream of len="+len); closeSocket(); return null; } } 

这已经多次被提及,但回复表明有些人对OutOfMemoryError这种(常见)恢复技术感到困惑。 检查我的post, 如果新的失败怎么办? 有关如何操作的演示。

我做过的唯一一个地方就是移动开发。 您可以要求用户关闭其他应用程序,以使您的应用程序能够正常工作。 但这不是Android开发的情况。

我没有看到你可以对这种情况做任何其他事情。 可能是,一些适当的日志记录或清理。

这不是例外; 这是一个错误:java.lang.OutOfMemoryError

当它从Throwable下降时你可以捕获它:

尝试{

//在这里创建大量对象并将它们藏在某处

} catch(OutOfMemoryError E){

//释放一些(所有)上述对象

}

但是,除非你正在做一些相当具体的事情(例如在特定的代码段中分配大量的东西),否则你可能无法捕获它,因为你不知道它会从哪里被抛出。

这是你永远不应该抓住的错误之一。 原因很简单,你无法在运行时对它做任何事情。 但是,如果您的应用程序经常遇到此错误,那么您应该考虑以下策略来缓解此问题 –

  1. 通过添加jvm args增加JVM可用的内存

-Xms1024m -Xmx1024m

  1. 如果错误仍然存​​在,那么使用JProfiler或Eclipse MAT等分析器来分析应用程序使用的内存量。

  2. 转到64位系统并进一步增加JVM内存。