直接回答:OOMKilled 是 cgroup 内存超限触发内核 OOM killer 杀容器进程,退出码 137。定位三步:kubectl describe pod 看 Reason 与上次终止状态;用 Prometheus 查容器内存曲线(container_memory_working_set_bytes 对 limits),区分“缓慢涨到顶”(泄漏或 limits 低估)与“瞬时尖峰”(批处理、大查询);配合应用日志与 heap dump 工具定位是谁在吃内存。

展开解析:运行时感知是最大的坑:JVM 老版本读宿主机内存算出巨大堆上限,容器里跑着跑着就被杀——JDK 8u191+ 与 JDK 11+ 支持容器感知(MaxRAMPercentage),显式设置 -Xmx 为 limits 的 60%~70% 留出堆外内存(元空间、线程栈、直接缓冲、JIT 代码缓存都在堆外)。Go 的 GC 以宿主机内存为参照,容器里应用 GOMEMLIMIT 对齐 limits。第二个坑:page cache 计入 cgroup 内存,写日志/读大文件快的容器可能“无辜”被杀,v2 与内核版本行为有差异。第三个坑:limits 与 requests 差距过大时节点超卖,内存紧张先杀 Burstable 的 Pod(QoS 顺序),关键服务要 Guaranteed(requests=limits)。缓解手段:VPA 推荐合理值、压测校准 limits、给批处理任务配独立的内存配额与 swap 策略(v1.22+ 可受控开启 swap)。

追问方向:working_set 与 rss 的区别?为什么内存 limit 杀进程而 CPU limit 只限速?

(约 490 字)