Linux下Java进程无故消失案的元凶:OOM Killer

OOM Killer Killed Java Process in Linux

Java进程在运行时突然挂掉,常见的原因有很多,例如代码本身的致命bug、JVM自身故障、内存泄漏触发JVM的OOM机制等,但是这些原因都属于主观原因,基本可以通过查看日志来发现。

事实上,Java进程还可能被动地结束。由于用户进程只是运行在操作系统之上的普通进程,享受着操作系统提供的资源,因此也受制于操作系统。在Linux下,就存在一个隐形的进程杀手:OOM Killer。这次通过一个案件,我们抓住了这个元凶。

案件记录

我们先来看一下案发现场:

一个普通的Spring Boot项目,被打成jar包,运行在Linux系统中。

我们可以用 ps -ef | grep java 命令在进程列表中找到它的身影:

UID PID PPID C STIME TTY TIME CMD root 14303 1 3 14:25 ? 00:04:07 java -jar spring-boot.jar

可以看到,这个Java进程的进程号(PID)是14303。

可是突然有一天,这个进程莫名其妙消失了,在进程列表里怎么也寻找不到。

查看项目日志

我们首先尝试从项目日志中查找痕迹,但是并没有发现任何异常和错误信息。排除了代码本身bug以及内存泄漏的嫌疑。

查看JVM致命错误日志

JVM在发生致命错误时,会产生一个日志文件:hs_err_pid_<进程号>.log,这个文件默认是在工作目录下。但是这次我们并没有发现这个文件,可以判断得出,JVM没有发生致命错误,因此嫌疑排除。

幕后黑手OOM Killer

排除了一系列主观原因后,我们可以断定Java进程是被杀掉的。

我们得知,在Linux操作系统中,一直潜藏着一个隐形的进程杀手:OOM Killer。它帮助Linux监视着内存资源,一旦内存资源即将耗尽,它就会挑出那个最占用内存的进程,然后毫不留情的杀掉它。

但是,这个杀手即使做得再漂亮,也会留下痕迹。

通过 dmesg -T | grep java 命令,我们发现了以下证据:

[Wed Jul 1 23:34:44 2020] Out of memory: Kill process 14303 (java) score 413 or sacrifice child [Wed Jul 1 23:34:44 2020] Killed process 14303 (java) total-vm:2405644kB, anon-rss:432252kB, file-rss:0kB, shmem-rss:0kB

原来在案发时,系统的内存资源所剩不多,进程号为14303的Java进程占用内存太多,被OOM Killer挑出并杀掉了。

至此真相大白,时间、地点、人物证据俱全,OOM Killer就是Java进程无故消失案的元凶!

案件后续

经历过这个案件以后,Java进程深知它必须保护好自己,不做出头鸟。

以前占用了那么多内存,也有它自己不对的地方,以后必须要控制好内存占用。这不,它再次启动时,用 -Xmx 参数限制了自己能够占用的最大内存:

java -jar -Xmx64m spring-boot.jar

通过设置一个合理的参数,Java进程以后再也没有被莫名其妙杀掉过了。

 

 

文章评论
${fromAuthor ? '郄正元' : '游客'} 作者 ${gmtCreate}
${content}
${subList.length}
发表评论
${commentToArticle ? '' : parentContent}
字数:0/${maxCommentLength}
该邮箱地址仅用于接收其他用户的回复提醒,不会泄露