找回密码
 立即注册
首页 业界区 业界 经典面试题目“OOM异常会导致JVM退出吗?” ...

经典面试题目“OOM异常会导致JVM退出吗?”

路逸思 2025-6-2 22:43:52
经典面试题目“OOM异常会导致JVM退出吗?
我的回答是“这要分情况看,对于守护线程来说,OOM并不会导致JVM退出;对于非守护线程来说,如果某个线程捕获了OOM异常并处理异常后线程并未退出,那JVM并不会退出;如果线程没有捕获Error异常,那么将由全局的异常处理器处理,默认的全局的异常处理器也会让当前这个发生异常的线程退出,但是如果这个线程是最后一个非守护线程,那么JVM会退出,如果不是,JVM并不会退出。
对于守护线程来说,OOM并不会导致JVM退出,这里有一个非常好的线上故障:https://blog.csdn.net/shuxiaohua/article/details/114658325 ,缺少的接收客户端请求的线程Acceptor是一个守护线程,并且因为OOM退出时,并没有让Tomcat退出。
下面介绍一下非守护线程的情况,这些非守护线程通常就是处理业务的线程。每一个写过Java的人都应该知道Java异常继承体系,如下图所示。
1.png

这里我们要注意一点,就是Exception和Error有共同的父类Throwable,这意味着异常和错误都可以在Java层捕获,例如:
  1. public static void main(String[] args) throws InterruptedException {
  2.     try{
  3.         // 每个整数数组的大小为4M
  4.         int[] array1 = new int[1_000_000];
  5.         int[] array2 = new int[1_000_000];
  6.         int[] array3 = new int[1_000_000];
  7.         int[] array4 = new int[1_000_000];
  8.         int[] array5 = new int[1_000_000];
  9.     }catch (Throwable t){
  10.         t.printStackTrace();
  11.     }
  12.     System.out.println("程序走到了这里!");
  13. }
复制代码
我们在指定参数-Xms20M -Xmx20m后,运行打印结果如下:
  1. java.lang.OutOfMemoryError: Java heap space
  2.         at cn.hotspotvm.TestError.main(TestError.java:12)
  3. 程序走到了这里!
复制代码
可以看到,即使发生了错误,这个线程依然在正常运行,如果我们不对Error进行捕获呢?如下:
  1. public static void main(String[] args) throws InterruptedException {
  2.     int[] array1 = new int[1_000_000];
  3.     int[] array2 = new int[1_000_000];
  4.     int[] array3 = new int[1_000_000];
  5.     int[] array4 = new int[1_000_000];
  6.     int[] array5 = new int[1_000_000];
  7.     System.out.println("程序走到了这里!");
  8. }
复制代码
再次运行后就的打印结果如下:
  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  2.         at cn.hotspotvm.TestError.main(TestError.java:10)
复制代码
可以看到,在发生错误时这个线程没有走到打印语句,而是直接退出了。
这里顺便说一下,我们可以设置一个全局的异常处理器来统一处理,或者优先针对某个线程设置异常处理器,这样当我们忽略了捕获错误时,可以在全局异常处理器中进行处理。举个例子如下:
  1. public static void main(String[] args) throws InterruptedException {
  2.     Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  3.         @Override
  4.         public void uncaughtException(Thread t, Throwable e) {
  5.             System.out.println("这里是全局异常处理 "+e.getLocalizedMessage());
  6.         }
  7.     });
  8.     int[] array1 = new int[1_000_000];
  9.     int[] array2 = new int[1_000_000];
  10.     int[] array3 = new int[1_000_000];
  11.     int[] array4 = new int[1_000_000];
  12.     int[] array5 = new int[1_000_000];
  13.     System.out.println("程序走到了这里!");
  14. }
复制代码
打印的信息如下:
  1. 这里是全局异常处理 Java heap space
复制代码
这个线程在全局异常处理中如果没有特殊处理,通常会让当前的线程退出。如果当前线程退出,那么JVM会退出吗?
其实Java虚拟机退出的条件是:虚拟机内已经没有了非守护线程。线程发生未处理的异常最终导致线程结束时,如果这个线程是最后一个非守护线程,则会退出,否则不退出。
更多文章可访问:JDK源码剖析网
2.png
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册