java - JVM 可以在不重新启动的情况下从 OutOfMemoryError 中恢复吗

标签 java jvm out-of-memory

  1. 如果 JVM 有机会在更多对象分配请求到来之前运行 GC,它是否可以在不重新启动的情况下从 OutOfMemoryError 中恢复?

  2. 不同的 JVM 实现在这方面有什么不同吗?

我的问题是关于 JVM 恢复,而不是用户程序试图通过捕获错误来恢复。换句话说,如果在应用程序服务器 (jboss/websphere/..) 中抛出 OOME,我是否必须重新启动它?或者,如果进一步的请求似乎没有问题,我可以让它运行吗?

最佳答案

它可能有效,但通常是个坏主意。无法保证您的应用程序将成功恢复,或者它会知道它是否没有成功。例如:

  • 确实可能没有足够的内存来执行请求的任务,即使在采取了恢复步骤(例如释放保留的内存块)之后也是如此。在这种情况下,您的应用程序可能会陷入循环,在该循环中它反复出现恢复,然后再次耗尽内存。

  • OOME 可以在任何线程上抛出。如果应用程序线程或库不是为处理它而设计的,这可能会使某些长期存在的数据结构处于不完整或不一致的状态。

  • 如果线程因 OOME 而死,应用程序可能需要在 OOME 恢复过程中重新启动它们。至少,这会使应用程序更加复杂。

  • 假设一个线程使用通知/等待或更高级别的机制与其他线程同步。如果该线程因 OOME 而死,则其他线程可能会等待永远不会到来的通知(等)......例如。为此进行设计可能会使应用程序变得更加复杂。

总之,设计、实现和测试应用程序以从 OOME 中恢复可能很困难,特别是如果应用程序(或运行它的框架,或它使用的任何库)是多线程的。最好将 OOME 视为 fatal error 。

另见 my answer到一个相关的问题:

编辑 - 回答这个后续问题:

In other words if an OOME is thrown in an application server (jboss/websphere/..) do I have to restart it?

不,您不必必须重新启动。但这可能是明智的,尤其是如果您没有一种好的/自动化的方式来检查服务是否正常运行。

JVM 将恢复正常。但是应用程序服务器和应用程序本身可能会或可能不会恢复,这取决于它们设计用于应对这种情况的程度。 (我的经验是,一些应用程序服务器不是为了解决这个问题而设计的,设计和实现一个复杂的应用程序来从 OOME 中恢复是很困难的,正确地测试它就更难了。)

编辑 2

回应此评论:

"other threads may be left waiting for notifies (etc) that never come" Really? Wouldn't the killed thread unwind its stacks, releasing resources as it goes, including held locks?

是的,真的!考虑一下:

线程 #1 运行:

    synchronized(lock) {
         while (!someCondition) {
             lock.wait();
         }
    }
    // ...

线程 #2 运行:

    synchronized(lock) {
         // do something
         lock.notify();
    }

如果线程 #1 正在等待通知,并且线程 #2 在 //做某事 部分中获得 OOME,那么线程 #2 将不会执行 notify() 调用,线程#1 可能会永远卡住,等待永远不会发生的通知。当然,线程 #2 保证会释放 lock 对象上的互斥锁......但这还不够!

If not the code ran by the thread is not exception safe, which is a more general problem.

“异常安全”不是我听说过的术语(尽管我知道你的意思)。 Java 程序通常不会被设计为对意外异常具有弹性。确实,在上述情况下,要使应用程序异常安全,可能很难甚至不可能。

您需要一些机制,从而将线程#1 的故障(由于 OOME)转变为线程#2 的线程间通信失败通知。 Erlang 会这样做……但 Java 不会。他们可以在 Erlang 中做到这一点的原因是 Erlang 进程使用严格的类似 CSP 的原语进行通信。即没有数据结构的共享!

(请注意,对于任何 unexpected 异常,您都可能遇到上述问题......而不仅仅是 Error 异常。有某些类型的 Java 代码试图从意外异常中恢复可能会以糟糕的方式结束。)

关于java - JVM 可以在不重新启动的情况下从 OutOfMemoryError 中恢复吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3058198/

相关文章:

java - 在远程方法调用期间,Java 平台是否用其 stub 替换所有远程对象?

java - 在 Recyclerview 适配器中实现 onClick

java - 你能估计一下 Java 会增加多少堆吗?

android - 如何在应用程序中存储大数据?

java - 如何访问对象内部的元素

javascript - Java Nashorn 使用 webEngine 事件

java - Java 编译器或 JVM 可以交换独立指令的指令顺序吗?

.net - 什么是交叉编译器和跨平台?

缓存中有内存时Linux内核模块OOM

java.lang.OutOfMemoryError : Compressed class space 错误