开放问答
K8s 里 Java 服务频繁 OOMKilled 但堆内远未到 -Xmx,怎么定位堆外/native 内存?
该问题的正文、回答与评论。
提问者 程清和-227 · 状态 open
SREK8sJVMOOMKilled内存排查
【背景】 我做了 5 年 SRE,主责一条 Java 微服务链路(JDK 17 + Spring Boot 3,跑在 K8s 1.28,Pod limit 内存 2Gi,JVM 配了 -Xmx1400m -XX:MaxMetaspaceSize=256m)。
【现象】 近两周该 Pod 平均每天被 OOMKilled 3~4 次,事件 reason=OOMKilled、exitCode=137。诡异的是每次 kill 前抓的 heap dump(JVM 侧)堆内 used 只到 ~900m,离 1400m 的 -Xmx 还有很大余量,metaspace 也没涨,GC 日志没有 Full GC 堆积。也就是说「JVM 自认为内存很健康」,但容器层却把它杀了。
【已尝试的排查与结果】
- 看了 Pod 的 cgroup memory.current,被杀前确实顶到 ~2Gi;
- 用 pmap 看过一次进程 RSS,比 -Xmx 多出约 600~700m,怀疑是 native/堆外;
- 开了 -XX:+HeapDumpOnOutOfMemoryError,但因为是容器被 SIGKILL,JVM 根本没机会 dump;
- 怀疑 DirectByteBuffer / netty / glibc malloc 碎片,但没法定位具体是哪块。
【期望得到的答案形态】
- 一套「堆内未满却被 OOMKilled」的系统排查步骤与命令(比如如何看 RSS 构成、如何区分 native 与堆外、如何抓 pmap 快照对比);
- 有哪些常见元凶清单(native 库、堆外、线程栈、JNI、页缓存等)及各自的特征;
- JVM 参数层面有什么可以加来「让容器 kill 之前先留证据」的做法(如 -XX:+ExitOnOutOfMemoryError、-XX:NativeMemoryTracking、JFR 等)。 如果能给一个可复现的排查 checklist 就更好了。
评论
暂无评论。