线上OOM需“捕获现场+快速归因+精准干预”:配置-XX:+HeapDumpOnOutOfMemoryError自动保存hprof,结合GC日志区分泄漏型(MAT查Dominator Tree/Leak Suspects)与峰值型(限流、分页优化),禁用盲目调堆、手动GC等误操作。

线上服务偶发内存溢出(OOM)比稳定复现的更难定位,但并非无迹可寻。关键在于“捕获现场+快速归因+精准干预”,而不是盲目调大堆内存。
配置自动堆转储(Heap Dump)
让 JVM 在 OOM 发生时自动生成快照,这是后续分析的唯一可靠依据:
- 启动参数中加入:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps/ - 建议同时加
-XX:+PrintGCDetails -Xloggc:/path/to/gc.log,记录 GC 行为辅助判断是泄漏还是瞬时压力 - 确保 dump 目录有足够磁盘空间和写权限;生产环境建议用绝对路径,避免因工作目录变动导致 dump 失败
区分泄漏型 vs 峰值型 OOM
拿到 dump 文件后,先用 MAT 或 VisualVM 快速判断性质:
- 泄漏型:dump 中存在大量相同类型对象(如未关闭的 Connection、缓存未清理的 DTO、静态 Map 持有业务对象),且 dominator tree 显示它们被某条长引用链持续持有
- 峰值型:dump 中对象种类分散,但某次请求触发了大批量数据加载(如分页失效查全表)、或突发流量打满堆空间——此时 GC 日志会显示频繁 Full GC 且老年代使用率持续攀高
针对性加固与监控
根据归因结果落地防护措施:
立即学习“Java免费学习笔记(深入)”;
- 若确认是内存泄漏:修复代码中资源未释放(数据库连接、流、线程池任务)、集合未清理、监听器未反注册等问题;对缓存加 size 限制 + LRU 策略,禁用无上限的 static 集合
- 若属峰值压力:在关键入口加限流(如 Sentinel QPS 控制)、查询层强制分页/游标、大对象处理改用流式响应(Spring WebFlux 或 ResultSet streaming)
- 补充运行时监控:通过 Micrometer + Prometheus 暴露
jvm.memory.used、jvm.gc.pause、java.lang:type=MemoryPool,name=PS Old Gen等指标,设置老年代使用率 >85% 的告警
避免常见误操作
有些做法看似缓解,实则掩盖问题或引入新风险:
- 仅调大
-Xmx而不分析 dump:可能延缓崩溃,但泄漏仍在累积,最终仍会 OOM,且拖慢 GC - 频繁手动
System.gc():干扰 JVM 自身回收节奏,反而加剧 STW 时间,不推荐 - 用 SoftReference/WeakReference 替代强引用缓存:适合读多写少场景,但不能解决根本泄漏,且易造成缓存击穿
- 忽略元空间(Metaspace)OOM:JDK8+ 后永久代移除,类加载过多(如热部署、动态代理泛滥)会触发
java.lang.OutOfMemoryError: Metaspace,需单独监控并加-XX:MaxMetaspaceSize


















