JVM 是如何死于 OOM 异常的?

How does a JVM die due to an OOM exception?

我查了很多地方都找不到 JVM 因 OOM 而死机的原因。我不考虑 OS 杀手。为了提供一些上下文,我有一个 Java 应用程序 运行ning 并且它开始 运行 内存不足,我知道它可能会在 JVM 开始终止线程后存活下来。

但是,我已经看到它在第一次 OOM 后 运行ning 超过 30 分钟,并且它一直 运行ning 处于这种无响应状态,它可能会恢复也可能不会恢复。但是,我也看到它在复制相同的步骤来触发 OOM 后,在第一个 OOM 之后立即崩溃。系统在内存方面很好,问题出在 JVM 上。所以,我的问题是:

  1. 在 OOM 期间 JVM 会发生什么情况,它可能会崩溃或永久保持无响应状态?
  2. JVM 如何杀死线程?是随机的吗?

从技术上讲,OutOfMemoryError 只是“另一个可抛出的对象”,因此它 可能会也可能不会 杀死它被抛入的线程,具体取决于线程如何处理它的例外情况。

例如,如果它在最低级别有一个 catch (Error e) 块,那么它可以“承受”很多问题,同时仍然 运行ning。

因此,如果您的 OutOfMemoryError 仅被抛入能够优雅地处理此类错误的线程中,那么您的系统可以继续正常工作。

但这也是 OutOfMemoryError 的 2 个不寻常的 属性 发挥作用的地方:

  1. 它基本上可以在任何地方分配内存的地方抛出,确切地它会被抛出的地方是如此不可预测,以至于看起来随机。它经常被扔在分配最多内存的地方,但这并不总是正确的。
  2. 由于错误条件的性质,它表示很可能 运行 在尝试处理异常时再次陷入完全相同的错误(例如,您可能 运行 内存不足而试图生成有关 运行ning 内存不足的日志消息)。这种递归性质使得可靠地处理 OOME 非常困难。

如果您想 真正 对应用程序中的 OOM 有弹性,您必须确保 所有线程 优雅地处理 OutOfMemoryErrors 或在它们不正确时正确重新启动(通过看门狗或类似的东西)。这通常很难做到,尤其是在使用任何创建自己的线程的库时。

因此 tl;dr 您问题的答案是:

  1. “这取决于”您的线程如何处理异常
  2. 线程将因未能处理初始异常或未能处理在尝试处理初始异常时发生的异常而被终止。哪个线程受到攻击是如此难以预测,以至于看起来随机。