4

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

相关的有:

捕获 java.lang.OutOfMemoryError?

是否可以在java中捕获内存不足异常?

4

4 回答 4

5

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

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

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

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


亚伦·迪古拉说:

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

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

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

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

  • 如果线程应该通知其他线程,那么该通知将永远不会发生,并且其他线程将被卡住等待。

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

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

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

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

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

因此,成功恢复的先决条件是:

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

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

于 2012-11-22T09:36:23.490 回答
4

是的。GC 在 之前运行OutOfMemoryError并且它继续工作。

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

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

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

于 2012-11-22T08:57:24.940 回答
2

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

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

于 2012-11-22T08:58:36.373 回答
0

在 OOME 的 javadoc 中,它说:

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

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

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

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

于 2012-11-22T08:55:53.070 回答