【问题标题】:Does garbage collection run after OutOfMemoryError is thrown in java?在 Java 中抛出 OutOfMemoryError 后是否运行垃圾收集?
【发布时间】:2012-11-22 08:42:41
【问题描述】:

似乎应该如此。但有人可以肯定或否认吗?

相关的有:

Catching java.lang.OutOfMemoryError?

Is it possible to catch out of memory exception in java?

【问题讨论】:

  • 我希望JVM在抛出OOME之前尝试运行垃圾收集...
  • @Yaneeve 如果您已经看过该问题及其答案,您的问题是什么? JVM是否再次尝试抛出错误之前所做的相同的事情,看看结果是否不同?
  • @arne.b 是的,也就是说,如果我释放任何强可达对象,它现在是否会被垃圾收集(或者会进行尝试)
  • @SeanOwen 是的,我的意思是之后

标签: java error-handling garbage-collection


【解决方案1】:

在java中抛出OutOfMemoryError之后是否运行垃圾收集?

它肯定会在 OOME 被抛出之前运行。事实上,OOME通常被抛出,因为垃圾收集器发现它无法回收足够的空间来满足分配请求1

它是否在 OOME 被抛出之后运行取决于应用程序的作用。如果应用程序尝试继续,则 GC通常会在应用程序下次请求更多内存时运行......在其继续执行中。

1 - 实际上,可以将 GC 配置为在检测到垃圾收集花费过多时间时抛出 OOME。在这种情况下,JVM 很可能有大量可用的未分配内存。


亚伦·迪古拉是这么说的:

因此,在精心设计的应用程序中,您可以捕获并处理 OOME,该程序将继续存在并继续工作。

这是真的,但出于两个不同的原因,这不是您通常应该做的事情。

第一个原因是线程尝试分配内存的任何地方都可能抛出 OOME。无论 JVM 当时在做什么都将被终止……直到 OOME 被捕获。例如:

  • 如果线程正在更新共享数据结构(处于锁定状态),则数据结构将保持半更新状态。

  • 如果线程本应通知其他线程,则该通知将永远不会发生,其他线程将一直等待。

  • 如果线程没有捕捉到 OOME,那么它将退出,如果没有其他注意到,那么您可能会留下一个不再工作的应用程序。

问题在于这些“破损”很难检测或预测,也很难从中恢复。

第二个原因是 OOME 通常表示以下情况之一:

  • 您试图在堆内存不足的情况下执行计算。如果您尝试从 OOME 中恢复,您可能会再次遇到同样的问题。

  • 您的应用程序存在内存泄漏;即应用程序中的某些数据结构保留对“垃圾”对象的引用,并防止它们被回收。如果您尝试从 OOME 中恢复,则很有可能什么都不会改变,而且您会一次又一次地遇到同样的问题。

所以,成功恢复的前提是:

  • 知道 OOME 不会损坏 JVM 中的任何重要内容,并且
  • 知道你不会再次遇到 OOME ...因为根本原因仍然存在。

在大多数应用程序中,这些都是必须满足的硬性前提条件。如果不满足这些条件,那么尝试从 OOME 中恢复很有可能会使其处于更糟糕的状态,而不是退出并重新启动应用程序。

【讨论】:

    【解决方案2】:

    是的。 GC 在OutOfMemoryError 之前运行,它会继续工作。

    OOME 与任何其他错误一样是一个错误:这意味着运行时可能处于有问题的状态,但这不会停止 Java。所以当你发现错误时,你可以删除一些引用,错误就会消失。

    问题当然是,当您尝试查找对 cut 的引用时,您无法知道其他代码(例如在另一个线程中)是否需要内存,并且该代码可能会引发另一个 OOME 并致命地中断。

    因此,在精心设计的应用程序中,您可以捕获并处理 OOME,程序将继续存在并继续工作。

    【讨论】:

    • 对不起 Aaron,@StephenC 的回答比你的更详细,但你的回答同样好而可靠
    【解决方案3】:

    如果你的问题真的是它是否运行之后 OutOfMemoryError:是的。它也在之前运行。 OutOfMemoryError 不会终止 JVM;它被抛出而不是对象分配成功并且程序继续。 JVM 继续,包括垃圾收集。

    事实上,像Tomcat这样的一些框架就是为此而设计的。他们分配了一点未使用的内存,在OutOfMemoryError的情况下,释放它,以便有足够的空间来完成有序的关机。这要求 GC 继续运行。

    【讨论】:

    • 要决定选择哪个答案是一个非常艰难的选择,你的答案还是@AaronDigulla 的答案。他说得更明确一些。不过,我确实喜欢你的 Tomcat 示例!
    【解决方案4】:

    在 OOME 的 javadoc 中,它说:

    当 Java 虚拟机无法分配对象时抛出,因为 内存不足,无法再提供内存 垃圾收集器。

    这意味着它在错误之前运行。

    顺便说一句,当你遇到这样的错误时,很难恢复,因为你不能保证有足够的内存来做其他事情。如果你使用了内存的最后一个字节,你就会被卡住。如果您因为尝试一次性分配 4Gb 而出现此错误,那么您仍然有机会拯救您的灵魂,但如果您需要这些 4Gb 来继续,那么您又被卡住了。

    http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/OutOfMemoryError.html

    【讨论】:

      猜你喜欢
      • 2017-03-02
      • 2012-01-19
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多