“Java进程咋又突然没了?还没任何报错,都好几天了好奇怪啊。”
上午刚上班不久,旁边的同事就遇到了棘手的技术问题。大概打听下,原来是某个Java应用在执行某个耗时的定时任务的过程中,大概率进程会突然退出,而且应用日志、中间件日志都找不到任何异常。听起来还挺有意思,我默默地登上了出问题的docker容器。
0x01 OOM killer
登上机器后,查看应用和中间件日志,确实没有看到问题。我怀疑是JVM OOM了但没有配置输出,正想加上OOM时的堆栈输出参数,但发现应用启动命令已经包含类似的参数:-XX:+HeapDumpOnOutOfMemoryError -XX:ErrorFile=./hs_err_pid<pid>.log -XX:HeapDumpPath=./java_pid<pid>.hprof
。
看来从应用层面查不到什么了,那就再看看系统日志吧。
使用dmesg -T | grep java
查看系统日志
果然,从dmesg
倒数第二行返回的信息来看,确实是由于oom导致的,但是这里的oom并非JVM的oom,而是Linux系统的oom。
Killed process xxx(java), total-vm:7539096kB, anon-rss:3919048kB file-rss:17312kB, shmem-rss:0kB。
在这台物理内存为4GB的机器上,
`total-vm`是已经分配给java进程的虚拟内存数量(7539096kb=7.02GB)
`anon-rss`是java进程物理内存使用量(3919048kB=3.65GB)
`file-rss`是java进程映射到设备或文件系统的使用量(17312kB=16.51MB)
网上已经有很多介绍Linux oom killer的文章了,这里只简单概括:Linux系统在分配物理内存时,如果内存不足(什么时候不足?)oom killer会选择oom score得分最高的进程杀掉以释放内存。