首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么JVM可以自己从OOM Java堆空间中恢复

为什么JVM可以自己从OOM Java堆空间中恢复
EN

Stack Overflow用户
提问于 2022-07-05 06:44:35
回答 2查看 103关注 0票数 0
代码语言:javascript
复制
Integer[][] data = new Integer[1000000][100000];

作为上面简单的演示代码,我尝试在pandora容器中应用非凡的大内存并触发OOM (这是阿里巴巴开发的一个网络容器,就像tomcat一样)。但是这个错误似乎只影响到当前的请求,web服务不会被折叠;正如我所知,与异常不同,java中的错误不应该恢复,并且影响整个过程。我很困惑,请advice..thanks。

EN

回答 2

Stack Overflow用户

发布于 2022-07-05 08:10:38

首先,这是:

正如我所知,

与异常不同,java中的错误不应该恢复,并影响整个过程。

一般来说,这是事实。在web容器的情况下,在请求线程上从OOME恢复比典型的多线程应用程序更有可能成功。

为什么?

因为在一个工作线程上处理一个web请求所做的工作通常独立于其他线程。这意味着请求中的OOME不太可能使共享数据结构处于不一致的状态。

但你仍然有一个问题,那就是OOME的根本原因可能是内存泄漏.当web容器清理请求线程并创建一个新线程时,这种情况很可能不会消失。因此,对于一个网络容器来说,从OOME中恢复还是值得怀疑的。

但无论如何,这是相当普遍的行为。我认为理由是,试图以一个合理的机会成功比失败快。

那么,为什么有可能恢复呢?

考虑一下这个片段:

代码语言:javascript
复制
   public void test() {
       try {
           Integer[][] data = new Integer[1000000][100000];
       } catch (OutOfMemoryError ex) {
           // log it
       }
       // do something else
   }

意见:

  1. 是在GC运行后发生的OOME。导致OOME的JVM操作的典型序列如下:

代码语言:javascript
复制
- Attempt to allocate large object
- Find there is not enough free space
- Run a new space GC
- Try the allocation again.
- Still not enough free space
- Run a full GC
- Try the allocation again.
- Still not enough free space
- Throw OOME

  1. new Integer[10000][10000]是一件无所不包的事情。如果它触发了一个OOME,那么到目前为止它分配的对象都是不可访问的。因此,如果// do something else代码试图分配另一个对象,而堆仍然满,那么JVM将再次运行GC .会回收那些无法到达的物体..。我们又开始做生意了。--

  1. 即使不是..。当data超出范围时,它所引用的Integer[][]Integer[]对象树现在可能会被GC.

检测到。

如果在子线程上抛出OOME,并且允许线程死亡,则

  1. 将无法再访问该线程的所有局部变量。这会导致更多(潜在的)无法到达的对象。

关键是,在从OOME中捕获和恢复的时候,可能会有一些可收集的垃圾。

那么,如果有可能恢复,为什么人们建议反对从海洋生态系统中恢复呢?

  1. ,因为OOME的原因可能是内存泄漏。从内存泄漏引起的OOME中恢复可能导致性能低下。堆最终会填满GC花费太多时间的点。

  1. ,因为OOME会导致数据结构处于不一致的状态;例如,当它得到OOME.

时,您的代码正在更新它。

  1. ,因为OOME可以破坏并发行为。例如,假设线程A正在等待来自线程B的notify。如果B获得OOME,它可能会完全死掉,或者它可能试图恢复.当它的锁被释放的时候。无论哪种方式,线程A都有可能永远被卡在一起,等待永远不会发生的通知。(线程B可能会触发应用程序关闭以避免这种情况。)
票数 1
EN

Stack Overflow用户

发布于 2022-07-05 07:05:36

错误OutOfMemoryError: Java heap space类似于任何其他异常,它只会导致当前线程终止。这只是关于耗尽Java堆空间的问题。因此,如果线程被杀死,并且该线程中创建的所有对象都无法访问并可能被收集,那么就有足够的堆空间继续运行,并且整个应用程序没有理由崩溃。

只有当应用程序超出操作系统所能提供的内存时,应用程序本身才会被操作系统杀死。但是,您可以在一些JVM中使用一些键显式地崩溃任何内存不足的错误,例如-XX:+CrashOnOutOfMemoryError

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72865015

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档