参考文章:JVM OOM异常会导致JVM退出吗?
结论是:OOM是针对线程的,哪个线程OOM了,JVM是释放掉该线程所有的资源。然后其他线程继续运行,JVM不会退出。
JVM退出的条件是:虚拟机内不存在非守护线程。
下面是我的demo测试:
public class OOMTest {
public static void main(String[] args) throws InterruptedException {
int i=0;
while (true){
if(i > 0){
System.out.println("main thread");
Thread.sleep(1000L);
continue;
}
Thread t1 = new Thread(() -> {
List<OOMObject> refs = new ArrayList<>();
while (true){
OOMObject o1 = new OOMObject();
refs.add(o1);
System.out.println("thread-1申请1M");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() -> {
List<OOMObject> refs = new ArrayList<>();
while (true){
OOMObject o1 = new OOMObject();
refs.add(o1);
System.out.println("thread-2申请1M");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
i++;
}
}
static class OOMObject {
byte[] tempbytes = new byte[1024*1024];
}
}
运行的结果如下:
thread-1申请1M
main thread
thread-2申请1M
thread-1申请1M
main thread
thread-2申请1M
main thread
thread-1申请1M
thread-2申请1M
main thread
thread-1申请1M
thread-2申请1M
main thread
。。。//省略一些
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
at com.example.demo.stream.OOMTest$OOMObject.<init>(OOMTest.java:56)
at com.example.demo.stream.OOMTest.lambda$0(OOMTest.java:24)
at com.example.demo.stream.OOMTest$$Lambda$1/1104106489.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
//这里看到Thread-0线程OOM了,JVM会结束该线程并释放掉它所占用的内存(几乎是一半内存)。然后t2线程继续执行。
thread-2申请1M
main thread
thread-2申请1M
main thread
thread-2申请1M
main thread
thread-2申请1M
main thread
。。。//省略一些
Exception in thread "Thread-1" java.lang.OutOfMemoryError: Java heap space
at com.example.demo.stream.OOMTest$OOMObject.<init>(OOMTest.java:56)
at com.example.demo.stream.OOMTest.lambda$1(OOMTest.java:38)
at com.example.demo.stream.OOMTest$$Lambda$2/812265671.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
//这个时候t2线程也OOM了,JVM结束t2并释放它所占内存。并让主线程继续执行。
main thread
main thread
main thread
main thread
main thread
main thread
main thread
main thread
上面从日志打印来验证的。我们来从JVM的gc看:
image.png
这个图执行的时间有点久,所以你可以看到最后main thread在执行的时候,old几乎为空。这个不用管,重点看下红色框框的内容。
在第一个红色框,old满的之后,立即清理掉t1所占空间,以让t2继续执行。然后t2继续填满t1释放的内存后,它自己也OOM了。JVM释放t2所占内存,那就几乎是所有空间了。所以,main线程运行的时候old几乎为空。
PS:查看上图的gc用jvisualvm,但是需要给它安装个插件Visual GC。
安装插件文档:https://pan.baidu.com/s/19IeeGQnKcYEVpOqJtRsd_w,提取码:uzr1
网友评论