开放问答
容器内存未超 limit 却频繁 Full GC + Pod 被驱逐:堆外/Native 内存如何定位?
该问题的正文、回答与评论。
提问者 程寒山-877 · 状态 open
JVMKubernetescgroup内存FullGC
【背景】 我做性能优化 10 年,最近带团队复盘一个 Java 17 的订单服务:K8s 1.28.9 + cgroup v2,Pod 规格 8C16G,JVM 参数 -Xmx8g -Xms8g -XX:+UseG1GC,跑 4 副本,QPS 约 2w,P50 稳定在 25ms。
【现象】 过去两周 P99 从 30ms 漂到 180ms 左右,且每周 2–3 次某个副本被 K8s 驱逐(Event 显示 MemoryPressure / OOMKilled)。关键矛盾点:
- kubectl top 看到的 working_set 峰值只有 11G,远低于 16G limit,但驱逐前 30s 内核 dmesg 有 oom_kill 记录;
- JVM 自身 GC log 显示这些时段 Full GC 明显增多,单次 400–900ms,但 Old Gen 使用率峰值才 65%;
- 业务代码里有 Netty(直接内存)+ 一个 RocksDB 本地缓存(堆外),怀疑是 Native 内存挤占了 cgroup 视角下的内存。
【已尝试】
- 加了 -XX:NativeMemoryTracking=summary,看 MALLOC / INTERNAL 项;
- 上了 async-profiler 抓 on-cpu,看不到明显热点;
- 没上 jcmd VM.native_memory 的 detail 对比(担心线上开销)。
【期望答案形态】 想请大家给一套可复现的排查清单:在容器里怎么把 heap、direct、mmap、page cache 这几块账分开算?NMT detail 对比两次快照在线上跑是否安全?有没有比 OOM 前更早的告警信号(比如 PSI 或 cgroup memory.events)可以提前 1–2 分钟预警?最好能附上你们踩过的类似案例与最终参数。
已采纳
回答者
回答正文
评论
暂无评论。