美团二面:OOM后,JVM一定会退出吗?为什么?90%的人都会答错

185 阅读4分钟

先说结论:Java应用OOM了,JVM不一定会挂

为什么OOM了,JVM却没挂?

我们经常说“OOM(OutOfMemoryError)一发生,程序就挂了”,但你会发现现实中很多时候:OOM是发生了,可JVM还在运行。这到底是咋回事?

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。 这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软


OOM 本质上是个异常

先来看看 OutOfMemoryError 是什么。它其实就是 Java 中的一种异常,准确点说,是 Error 类的一种,属于非检查异常(unchecked exception),不会强制要求你捕获或声明。

 

它的触发机制很简单:当 JVM 在给某个线程分配内存时,发现堆空间不够用了,就会抛出这个异常。但注意,这个异常是抛给当前线程的,而不是整个 JVM。

Java 的线程模型是“线程独立”:每个线程自己的事自己处理。一个线程就算挂了,也不影响别的线程继续跑。这点在异常处理机制上也体现得很清楚。


OOM 只会终止当前线程

线程的核心执行逻辑在 run() 方法里,这个方法不能声明抛出任何检查异常。

所以,一旦有异常(比如 OOM),要么你手动 try-catch 处理,要么它就会被线程的默认异常处理器接管,最终导致这个线程终止。

但线程终止 ≠ JVM 崩溃。只要还有其他线程(尤其是非守护线程)在跑,JVM 就不会退出。


JVM什么时候才会“挂”?

JVM退出的条件非常明确:所有非守护线程都结束了,JVM 才会退出

 

所以,即使某个线程因为 OOM 挂了,只要其他非守护线程还在跑,整个 JVM 就能继续撑下去。这也解释了为啥“发生了 OOM,JVM 却还活着”。


如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题、简历模板、算法刷题


举两个例子你就明白了

示例 1:普通线程 OOM,JVM 照样跑

假设你有两个线程,一个在分配内存时发生了 OOM,它挂了,另一个还在正常执行打印日志。那么 JVM 就继续运行,不会退出。

打印内容可能长这样:

我还行...
我还行...
我还行...

说明主线程完全没受到影响。


示例 2:线程池里 OOM,线程还在继续跑

如果你用的是线程池,就更明显了:某个 task 抛了 OOM,当前任务结束了没错,但线程池里的那个线程本身并不会终止,它还能继续接收别的任务。

即使线程池发生了内存溢出,只要主线程还在(而且不是守护线程),JVM 也不会死。


JVM 真正“死”的情况?

那OOM 到底什么时候才会让 JVM 真挂掉?主要有两种情况:

▶ 场景一:主动挂

假设你所有的非守护线程都在不停地申请内存,最终全挂了,那 JVM 就只能跟着退出。这叫主动退出。这时候,JVM 真的已经“油尽灯枯”了,啥都干不了了。

▶ 场景二:系统级别的 OOM Killer 出手

如果你的程序不仅撑爆了 JVM 的内存,还拖累了整个系统,操作系统的 “OOM Killer” 就会上场,把你这个“吃内存大户”干掉。这时候 JVM 是被动下线的。

Linux 内核在系统内存不足时,会评估哪个进程最“坏”(占用最多资源),然后直接杀掉。这叫被动退出。


✅ 总结一句话:

OOM 不等于 JVM 挂了,只有所有非守护线程都挂了或者被操作系统强制干掉时,JVM 才真的退出。


如你所见,这就是一个看似“程序挂了”的误区,其实只是线程挂了,而不是 JVM 真挂了。


最后说一句(求关注,求赞,别白嫖我)

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。 这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软

本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享

求一键三连:点赞、分享、收藏