美文网首页后端汇总
发生OOM了程序一定会退出吗

发生OOM了程序一定会退出吗

作者: 少年_7b60 | 来源:发表于2020-03-07 21:43 被阅读0次

    答案是不会,下面会给出分析和验证

    先看下OOM

    OOM全称OutOfMemoryError,是一个异常,属于Error系非受检异常,继承自
    Throwable->Error->VirtualMachineError
    当某一个线程中的在执行时申请不到足够的内存,就会抛出该异常

    OOM具体分要分是哪里OOM的,常见的有,还有其他情况

    • 堆溢出 java.lang.OutOfMemoryError: Java heap space,
    • 永久带溢出 java.lang.OutOfMemoryError:Permgen space
    • 不能创建线程 java.lang.OutOfMemoryError:Unable to create new native thread

    JVM何时会退出

    当进程只有守护进程时

    一个线程中发生堆OOM是否会导致JVM退出?

    答案是不会

    使用如下代码测试

    /*-Xms16m -Xmx32m*/
        public static void main(String[] args) {
    
            long maxMemory = Runtime.getRuntime().maxMemory();
            long totalMemory=Runtime.getRuntime().totalMemory();
    
            System.out.println(String.format("maxMemory: (%.2f M)", (double) maxMemory / (1024 * 1024)));
            System.out.println(String.format("totalMemory: (%.2f M)", (double) totalMemory / (1024 * 1024)));
    
            new Thread(() -> {
                List<byte[]> list = new ArrayList<byte[]>();
                while (true) {
                    System.out.println(Thread.currentThread() + " alloc memory");
                    byte[] b = new byte[1024 * 10240 * 1];
                    list.add(b);
                    try {
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        System.out.println(Thread.currentThread() + " echo");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                    }
    
                }
            }).start();
        }
    

    执行结果如图


    当一个线程oom,代表堆不够用了,为什么其他线程不紧接着oom继而JVM退出呢

    个人觉得有3方面原因:

    1. 一个线程的异常不会抛到其他线程
    2. 线程发生OOM后会部分资源被回收
    3. 发生OOM是由于申请内存触发的,如果其他线程不申请资源,则也不会OOM

    第1个原因后续分析,先看内存回收情况
    这段时间内存图如下


    可以看到,当线程0抛出异常后,结果堆中内存立即得到了释放
    这是因为线程0申请的对象仅被线程0所引用

    此外,线程1 并没有申请任何资源,这意味着即使线程0OOM,且内存没被回收,线程1依然可以继续执行。将代码稍作修改,线程0 OOM后线程1依然可以继续执行,只是堆的空间维持在耗尽的状态,如图

    补充

    OOM可以catch吗?
    可以,一切Throwable都可以catch

    byte[] b = null;
    try{
        b= new byte[1024 * 10240 * 1];
    }catch (Error e){
        System.out.println(e.getMessage()+" "+b);
    }
    

    这段代码中,发生oom后,对象创建失败,会打印如下

    Java heap space null
    

    线程与异常的关系

    1. 线程不允许往外抛受检异常
      从方法签名public abstract void run();就可以看出
    2. 对于非受检异常,或是未能捕获的受检异常,会交给UncaughtExceptionHandler处理,具体过长如下
      当异常出现后,虚拟机调用
    private void dispatchUncaughtException(Throwable e) {
            getUncaughtExceptionHandler().uncaughtException(this, e);
    }
    
    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
            return uncaughtExceptionHandler != null ?
                uncaughtExceptionHandler : group;
        }
    

    一个线程为主动设置UncaughtExceptionHandler时,会由当前线程的group处理,group在init方法中初始化,它是ThreadGroup对象,有能力处理未捕获异常
    class ThreadGroup implements Thread.UncaughtExceptionHandler

    public void uncaughtException(Thread t, Throwable e) {
            if (parent != null) {
                parent.uncaughtException(t, e);
            } else {
                Thread.UncaughtExceptionHandler ueh =
                    Thread.getDefaultUncaughtExceptionHandler();
                if (ueh != null) {
                    ueh.uncaughtException(t, e);
                } else if (!(e instanceof ThreadDeath)) {
                    System.err.print("Exception in thread \""
                                     + t.getName() + "\" ");
                    e.printStackTrace(System.err);
                }
            }
        }
    

    从上面可以看出,它对异常的处理就是打印异常信息,结束后线程也就退出了

    参考资料

    https://mp.weixin.qq.com/s/8j8YTcr2qhVActLGzOqe7Q
    https://blog.csdn.net/w372426096/article/details/82851375
    https://www.cnblogs.com/myseries/p/12079708.html

    相关文章

      网友评论

        本文标题:发生OOM了程序一定会退出吗

        本文链接:https://www.haomeiwen.com/subject/qrlkdhtx.html