捕获OutOfMemoryError

时间:2011-03-23 10:40:35

标签: java out-of-memory

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

9 个答案:

答案 0 :(得分:11)

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

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

然而,请注意,通常情况下(除非您处于一次分配大量内存的位置),您可能不会特别针对这些情况捕获OutOfMemoryError,而是在主入口点的顶部一直catch Throwable

答案 1 :(得分:11)

黄金法则只是捕捉您可以处理的错误。如果您在OutOfMemory错误后可以做一些有用的事情,那么请继续。

答案 2 :(得分:7)

不,抓住ExceptionRuntimeException,但几乎没有(从'永远'改变)Error

  

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

注意:
我在这里引用官方的Javadocs。如果您不同意,请告诉Oracle,不要拍摄信使: - )

答案 3 :(得分:5)

正如其他一些答案所指出的那样,抓住OutOfMemoryError并尝试恢复 1 是一个糟糕的主意。而不是仅仅重复javadoc说你Error异常是不可恢复的,我会试着解释原因。

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


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

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


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

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


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


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

答案 4 :(得分:2)

如果您希望正常关闭以特定处理此情况。

如果您可能需要分配大型阵列并且希望正常降级系统,也可以使用它。

编辑:我用来检查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;
  }
}

答案 5 :(得分:2)

这已经多次被提及,但是回复表明有些人对OutOfMemoryError的这种(常见)恢复技术感到困惑。查看我的帖子What if new fails?,了解如何操作。

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

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

你可以从Throwable下降时抓住它:

  

尝试{

     

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

     

} catch(OutOfMemoryError E){

     

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

     

}

但是,除非你做了一些相当具体的事情(比如在特定的代码部分中分配大量的东西),否则你可能无法抓住它,因为你不知道它会被扔到哪里从

答案 8 :(得分:1)

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

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

    -Xms1024m -Xmx1024m

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

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