答案是不会,下面会给出分析和验证
先看下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方面原因:
- 一个线程的异常不会抛到其他线程
- 线程发生OOM后会部分资源被回收
- 发生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
线程与异常的关系
- 线程不允许往外抛受检异常
从方法签名public abstract void run();
就可以看出 - 对于非受检异常,或是未能捕获的受检异常,会交给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
网友评论