必须启用堆转储并指定路径:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/app/logs/oom_%p_%t.hprof,配套开启GC日志和jstack快照,针对Metaspace、Direct buffer等不同OOM类型设置对应参数限值。

Java 中内存溢出时默认会打印基础堆栈信息,但仅靠这个远远不够定位根因。真正有效的做法是让 JVM 主动捕获现场、保留证据,并输出可分析的诊断数据。
必须启用堆转储并指定路径
单加 -XX:+HeapDumpOnOutOfMemoryError 不会生成文件——它默认尝试写入启动目录,而生产环境通常无写权限或路径不可控,结果是静默失败。
- 正确写法:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/app/logs/oom_%p_%t.hprof
- %p 替换为进程 PID,%t 是秒级时间戳,避免多实例覆盖
- 目标目录需提前创建,且 JVM 启动用户对该目录有读写权限(如 chown app:app /opt/app/logs)
配套开启 GC 日志辅助时间对齐
OOM 往往伴随频繁 GC 或 GC 失败,GC 日志能帮你确认是否长期 Full GC、内存是否持续增长、是否卡在某个阶段。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- JDK 9+ 推荐:-Xlog:gc*:file=/opt/app/logs/gc.log:time,uptime,level,tags
- JDK 8 可用:-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/opt/app/logs/gc.log
- 建议加日志轮转防撑爆磁盘:-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M
让错误信息更完整:附加线程快照与系统上下文
堆转储反映“内存里有什么”,jstack 反映“当时线程在干什么”,两者结合才能还原 OOM 前一刻的真实状态。
立即学习“Java免费学习笔记(深入)”;
- 配置 -XX:OnOutOfMemoryError="sh /opt/app/scripts/oom-handler.sh %p"(注意绝对路径)
- 脚本中应至少包含:jstack %p > /opt/app/logs/jstack-$(date +%s).log
- 同时记录主机名、时间、服务名等上下文,方便关联监控和日志平台
不同 OOM 类型要针对性设限
不是所有 OOM 都发生在堆上,错误类型不同,参数重点也不同:
- Metaspace 溢出(java.lang.OutOfMemoryError: Metaspace):加 -XX:MaxMetaspaceSize=256m 并观察是否频繁回收
- 直接内存溢出(Direct buffer memory):设 -XX:MaxDirectMemorySize=512m(默认等于 -Xmx)
- 线程耗尽(unable to create new native thread):调小栈大小 -Xss256k,并检查系统级限制 ulimit -u


















