在Java中,当出现OutOfMemoryError时,垃圾收集是否会运行?

4

我希望JVM在抛出OOME之前尝试运行垃圾回收... - poussma
@ZNK-M 请查看 https://dev59.com/uWct5IYBdhLWcg3wKqUd - Yaneeve
@Yaneeve 如果你已经看过那个问题及其答案,那么你有什么问题?JVM是否会尝试再次执行之前发生错误的操作,以查看结果是否不同? - arne.b
@arne.b 是的,如果我释放了任何强可达对象,它现在会被垃圾回收(或尝试进行垃圾回收)。 - Yaneeve
@SeanOwen 是的,我确实是指之后。 - Yaneeve
4个回答

5
在Java中,OutOfMemoryError抛出前肯定会运行垃圾收集器。事实上,通常情况下,OOME是垃圾收集器发现无法回收足够空间以满足分配请求的结果而抛出的。当应用程序尝试继续运行时,是否在OOME抛出后运行垃圾收集器取决于应用程序的操作。如果应用程序尝试获取更多内存,垃圾回收器将通常在其持续执行期间运行下一次。在仔细设计的应用程序中可以捕获和处理OOME,并使程序继续工作。然而,这不是通常应该做的事情,原因有两个。首先,OOME可能在任何线程尝试分配内存的地方抛出,线程正在进行的任何操作都将被终止...直到OOME被捕获。此外,OOME通常表示以下情况之一:1.您尝试使用不足的堆内存执行计算。2.您的应用程序具有内存泄漏,即应用程序中的某些数据结构保留对“垃圾”对象的引用,并防止它们被回收。成功恢复的先决条件是:您知道OOME不会破坏JVM中的任何重要内容,并且您知道您不会再次遇到OOME,因为根本原因仍然存在。

这些是大部分应用难以满足的硬性前提条件。如果不符合这些条件,尝试从OOME中恢复很可能会使应用程序处于比退出并重新启动更糟糕的状态。


4

是的。垃圾回收会在OutOfMemoryError之前运行,并且它会继续工作。

OOME与其他错误一样:它意味着运行时可能处于有问题的状态,但这并不会停止Java。因此,当您捕获该错误时,您可以删除一些引用,该错误将消失。

问题当然在于,您无法知道其他代码(例如在另一个线程中)是否需要内存,而您尝试查找要削减的引用,该代码可能会抛出另一个OOME并导致致命错误。

因此,在经过仔细设计的应用程序中,您可以捕获和处理OOME,程序将继续工作并保持正常。


抱歉,Aaron,@StephenC的答案比你的更详细,但你的答案同样很好且扎实。 - Yaneeve

2
如果你的问题是关于程序是否会在OutOfMemoryError之后运行:是的,它也会在之前运行。 OutOfMemoryError不会终止JVM;相反,它被抛出而不是对象分配成功,程序将继续执行。JVM继续运行,包括垃圾回收。
事实上,一些像Tomcat这样的框架就是为此而设计的。它们分配了一些未使用的内存,在发生OutOfMemoryError时释放它,以便有足够的空间完成并进行有序关闭。这要求GC继续运行。

这真是一个艰难的选择,决定选择哪个答案,你的还是@AaronDigulla的。他的更加明确一些。不过我确实喜欢你的Tomcat示例! - Yaneeve

0
在 OOME 的 javadoc 中,它说:
“当Java虚拟机由于内存不足而无法分配对象,并且垃圾收集器不能提供更多内存时,就会引发此异常。”
这意味着它已经在错误发生之前被运行过了。
顺便说一句,当你遇到这种错误时,很难恢复,因为你不能保证有足够的内存来进行任何其他操作。如果你使用了最后几个字节的内存,那么你就被卡住了。如果你因为尝试一次性分配4GB而出现这个错误,那么你仍然有挽救的机会,但如果你需要这4GB来继续进行,那么你又陷入困境了。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接