线上Java服务OOM时自动保存Heap Dump需配置-XX:+HeapDumpOnOutOfMemoryError开关、-XX:HeapDumpPath指定绝对路径并验证权限、-XX:OnOutOfMemoryError执行临终脚本,同时检查磁盘空间、调整overcommit_memory及大堆场景优化。

要让线上 Java 服务在 OOM 发生的瞬间自动保存内存镜像(即 Heap Dump),关键不是“事后补救”,而是提前把 JVM 配置成具备“自取证”能力。核心在于三点:开关打开、路径可控、失败可查。
必须配置的 JVM 启动参数
仅加 -XX:+HeapDumpOnOutOfMemoryError 是远远不够的,它只是个开关,不指定路径默认写到启动目录,生产环境基本会静默失败。
- -XX:+HeapDumpOnOutOfMemoryError:强制启用 OOM 自动转储功能,JVM 不默认开启
- -XX:HeapDumpPath=/data/logs/java/dump/heapdump_%p_%t.hprof:指定绝对路径,%p 替换为进程 PID,%t 替换为 Unix 时间戳(毫秒级),确保多实例不冲突、文件名唯一
- (可选但推荐)-XX:OnOutOfMemoryError="sh /opt/scripts/oom-notify.sh %p":OOM 触发后立即执行脚本,可用于发告警、记录日志、清理临时资源等——注意:此时 JVM 已不可恢复,该命令只是“临终操作”
路径与权限必须人工验证
参数写对 ≠ 文件一定能生成。90% 的“没 dump 出来”问题都卡在这一步。
- 用 ps -eo pid,user,cmd | grep java 查看 Java 进程实际运行用户(比如 tomcat、appuser)
- 确认该用户对 -XX:HeapDumpPath 指定的目录有 w 权限:ls -ld /data/logs/java/dump/
- 手动创建目录并赋权:mkdir -p /data/logs/java/dump && chown appuser:appuser /data/logs/java/dump
- 检查磁盘空间:df -h /data,避免 OOM 前磁盘已满导致写入失败
大堆场景下的风险规避
堆内存超过 4GB 时,自动 dump 可能引发连锁反应,需提前干预。
- 转储过程会触发 Full GC,IO 和 CPU 压力陡增,可能拖垮节点甚至触发 Linux OOM Killer
- 建议提前运行:echo 1 > /proc/sys/vm/overcommit_memory,避免因内存分配策略导致 dump 中断
- 若堆大于 10GB,可考虑将 -XX:HeapDumpPath 指向 /dev/shm(内存文件系统),再由后台脚本异步移出,减少磁盘 IO 延迟
验证是否生效的实操方法
不要等真 OOM 才测试。上线前务必模拟验证。
- 用一个最小化测试类主动触发 OOM:new byte[Integer.MAX_VALUE]
- 观察目标目录是否生成 .hprof 文件,文件大小是否接近 -Xmx 设置值
- 用 jmap -histo:live
对比触发前后对象数量变化,确认 dump 内容合理 - 检查 JVM 启动日志,确认无 “Could not generate heap dump” 类错误提示










