线上 Java 服务发生 OOM,但流量还在进来,你会按什么顺序止损、取证和定位?
我的判断
OOM 处理中先保护整体服务并保留证据,再按堆、直接内存、元空间或本地内存分类定位;不能让所有实例同时导出大 dump。
告警后会立即把问题实例从流量池摘下,保留一两个现场实例,其他实例扩容或限流承接流量。先看异常类型、容器是否 OOMKilled、堆占用、GC、线程数和进程 RSS。只有磁盘和停顿风险可接受时,才在单个现场实例获取 heap dump;其余实例用 jcmd GC.class_histogram、NMT 或 JFR 做轻量取证。
不同类型走不同证据:
Java heap space:看 dominator、retained size 和对象到 GC Root 的引用链;Direct buffer memory:查 Netty 池、未释放 buffer 和MaxDirectMemorySize;Metaspace:看类数量和VM.classloader_stats,重点找无法回收的类加载器;- 容器被杀但堆不高:对账线程栈、本地库、文件映射和分配器。
修复要回到增长来源:无界缓存加容量和过期、监听器解除引用、批处理改流式。单纯加堆只能延后下一次事故。
01监控发现内存持续上涨
→02JVM 抛 OOM?
→03识别 OOM 类型
→04检查 OOMKilled 与 RSS
→05摘除实例并保存现场
容易答偏踩坑误区
- 所有 Pod 同时
-XX:+HeapDumpOnOutOfMemoryError。 可能瞬间打满共享磁盘。 - OOM 后立即重启且不留指标。 服务恢复了,但根因也消失了。
- 只看浅对象大小。 真正需要看对象保留的整棵引用图。