先查dmesg -t | grep -i "out of memory|killed process"确认内核oom日志,含“killed process pid (java) anon-rss:xxxkb”即坐实系统级oom;再查/var/log/messages或syslog比对committed_as与commitlimit,结合/proc/meminfo验证内存水位。

查 dmesg 里 OOM Killer 的原始日志
OpenJDK 进程被系统 OOM Killer 杀掉时,Linux 内核会直接写日志到 ring buffer,不经过 JVM。这是最权威、不可绕过的入口:dmesg -T | grep -i "out of memory\|Killed process"。输出中若含 Killed process 12345 (java) anon-rss:1890123kB,就坐实是 OS 级 OOM,不是 JVM 自己抛的 OutOfMemoryError。
注意加 -T 显示可读时间戳;如果 dmesg 输出为空,说明环形缓冲区已被刷掉,得立刻转去系统日志文件。
翻 /var/log/messages 或 /var/log/syslog
不同发行版落盘位置不同,必须按系统类型查:
- RHEL/CentOS:用
grep -i oom /var/log/messages - Ubuntu/Debian:用
grep -i oom /var/log/syslog或grep -i oom /var/log/kern.log
这些日志比 dmesg 更持久,包含触发时刻、被杀进程名、PID、当时 Committed_AS 和 CommitLimit 的快照值——关键是要看 Committed_AS > CommitLimit 是否成立,这才能确认是虚拟内存真正超支,而非缓存占位造成的误判。
确认是不是 JVM 自己 OOM,而不是系统杀的
很多人混淆两类 OOM:java.lang.OutOfMemoryError: Java heap space 是 JVM 在堆分配失败时自己抛的异常,会留在应用日志里;而系统 OOM 是内核直接 kill -9,进程瞬间消失,nohup 日志都来不及 flush。
快速区分命令:
- 查 JVM 日志:
grep -i "OutOfMemoryError" /path/to/app.log - 查系统日志:
dmesg -T | grep -i "out of memory"
两者不会同时出现。如果只在 dmesg 里看到 Killed process,但应用日志里没有 OutOfMemoryError,那 100% 是系统 OOM,和 JVM 参数无关。
结合 /proc/meminfo 验证内存水位
单看日志不够,得同步确认当时物理+虚拟内存是否真绷不住了:
- 运行
cat /proc/meminfo | grep -E "(Committed_AS|CommitLimit|MemAvailable|SwapFree)" - 重点比对
Committed_AS和CommitLimit:差值小于 100MB 就极可能触发 OOM -
MemAvailable低于 200MB 且SwapFree接近 0,说明物理内存也已枯竭
别信 free -h 的 available 字段——它是估算值,在 slab 缓存膨胀或大量 mmap 场景下严重失真。真实压力看 /proc/meminfo 里的原始字段。
查 OOM 记录本质是查内核行为,和 OpenJDK 版本无关。只要进程名是 java 或 java11,日志里就会体现;但如果你用了容器(Docker/Pod),/proc/PID/ 下的路径可能被 cgroup 隔离,得进容器 namespace 里查,或者用 docker inspect 找宿主机 PID 再查宿主机 /proc。











