启用Java OOM自动生成HeapDump需同时配置-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath=/abs/path,确保路径存在、权限正确、磁盘充足,并注意JVM参数顺序及工具分析优化。

Java OOM时自动生成HeapDump的关键参数
直接加 -XX:+HeapDumpOnOutOfMemoryError 就行,但光加这个远远不够——默认 dump 文件会写到 JVM 启动目录,而生产环境往往没权限、磁盘小、路径不可控,导致 dump 失败或找不到。
-
-XX:+HeapDumpOnOutOfMemoryError是开关,必须显式开启,JVM 不会默认做 -
-XX:HeapDumpPath=/path/to/dumps/必须指定绝对路径,且确保 JVM 进程对该路径有写权限(注意:不是当前用户,是启动 Java 的用户,比如java -user tomcat就得让tomcat用户能写) - 路径末尾建议加
%p或%t占位符,例如-XX:HeapDumpPath=/var/log/java/dump_%p.hprof,避免多实例冲突;%p是进程 PID,%t是时间戳 - 如果路径不存在,JVM 不会自动创建父目录,dump 直接静默失败(连日志都不打),务必提前
mkdir -p并chown
为什么加了参数却没生成 .hprof 文件
常见现象是 OOM 发生后,应用挂了,但目标目录空空如也。根本原因不是参数错,而是权限、路径、磁盘三重拦路虎。
- 检查
java进程实际运行用户:ps -eo pid,user,cmd | grep java,再确认该用户对-XX:HeapDumpPath指定路径有w权限 - 用
strace -e trace=openat,write -p $PID 2>&1 | grep hprof(在 JVM 还活着时试)可看到 dump 是否尝试写入及失败原因 -
df -h看目标分区是否满(特别是/tmp,很多人图省事设成-XX:HeapDumpPath=/tmp,结果 OOM 前磁盘已 99%) - JDK 8u92+ 默认禁用
HeapDumpOnOutOfMemoryError对某些 GC 类型(如 ZGC)的支持,若用新 JDK + 新 GC,需额外确认兼容性
要不要加 -XX:OnOutOfMemoryError 执行清理脚本
可以加,但别指望它“救活”进程——OOM 后 JVM 已进入不可逆终止流程,-XX:OnOutOfMemoryError 只是临终前的最后命令执行机会。
- 典型用法:
-XX:OnOutOfMemoryError="sh /opt/scripts/oom-notify.sh %p",%p 传入 PID,脚本能发告警、压缩刚生成的 hprof、清理临时文件 - 注意:脚本必须快速退出(
timeout 5s最好),否则阻塞 JVM 完全退出,造成进程僵死 - 脚本里别调
kill -9 %p—— JVM 自己正在杀自己,重复 kill 可能干扰信号处理 - 该参数不替代
HeapDumpOnOutOfMemoryError,两者是正交的:一个管 dump,一个管善后
HeapDump 文件太大,分析卡死怎么办
dump 文件动辄几 GB,用 jhat 或 Eclipse MAT 直接打开极易 OOM,不是配置问题,是工具本身限制。
立即学习“Java免费学习笔记(深入)”;
- 优先用
jmap -histo:live $PID > heap-histo.txt快速看类实例数量级,常比完整 dump 更快定位泄漏源头 - 生成 dump 时加
-XX:+UseContainerSupport(Docker 场景)并限制 JVM 内存上限,避免 dump 超过宿主机可用内存 - 分析前先用
hprof-conv(Android SDK 自带)或jdk/bin/jhsdb jmap(JDK 11+)做轻量裁剪,例如只导出对象引用链而非全部字段 - 别在生产机上分析 dump,拷到开发机再开 MAT;MAT 启动时加
-vmargs -Xmx4g,不然默认内存根本撑不住 2G+ 的 dump
最容易被忽略的是:JVM 参数顺序。像 java -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -jar app.jar 是对的,但如果把 -XX 参数放在 -jar 后面,就完全失效了——JVM 只认 -jar 前的参数。










