OOMKilled
Confirm a memory-related termination, understand the evidence, identify the memory pattern and choose a sustainable fix.
What does OOMKilled mean?
OOM means Out Of Memory. When Kubernetes reports a container termination reason of OOMKilled, the process was killed in a memory-exhaustion situation. A common case is the container exceeding its configured memory limit. First confirm the evidence rather than assuming every exit code 137 has the same cause.
60-second diagnosis
kubectl describe pod <pod> -n <namespace>
kubectl top pod <pod> -n <namespace> --containersNo → return to CrashLoopBackOff diagnosis
Step 1 — Confirm the termination reason
kubectl describe pod <pod> -n <namespace>Look under the affected container for:
Last State:
Terminated:
Reason: OOMKilled
Exit Code: 137Interpretation: OOMKilled is the strongest clue here. Exit code 137 means the process ended after SIGKILL; do not use 137 alone to prove the exact memory cause.
Step 2 — Find requests and limits
kubectl get pod <pod> -n <namespace> -o jsonpath="{.spec.containers[*].resources}"Memory limit: the container memory boundary enforced by the runtime/kernel mechanisms.
Usage: what the workload is actually consuming.
Step 3 — Inspect current and historical memory
kubectl top pod <pod> -n <namespace> --containersPOD NAME CPU(cores) MEMORY(bytes)
api-7d9 api 220m 486MiWhat to check: compare current memory with the container limit, but remember this is only a current snapshot. If the container already restarted, the peak that caused the kill may be gone. Current usage after restart may be misleading. In Prometheus/Grafana or your monitoring platform, inspect the period before the kill. Ask whether memory grows slowly, spikes with traffic, or jumps during startup.
Step 4 — Identify the memory pattern
A single snapshot cannot establish a leak. For a quick live check:
watch -n 5 kubectl top pod <pod> -n <namespace> --containersPrefer historical monitoring for the period before the kill.
Correlate memory with traffic, jobs and application events before concluding it is a leak.
kubectl describe node <node>
kubectl top node <node>Step 5 — Check runtime and process settings
kubectl get pod <pod> -n <namespace> -o yamlJVM
Look for -Xmx, MaxRAMPercentage and JAVA_TOOL_OPTIONS. If available:
kubectl exec <pod> -n <namespace> -- jcmd 1 VM.flagsHeap is not the whole container footprint; native/runtime memory needs headroom.
Node.js
Inspect NODE_OPTIONS and --max-old-space-size. V8 heap is not necessarily total process memory.
Python / multi-worker servers
Check worker count, caches, queues and batch size. If available:
kubectl exec <pod> -n <namespace> -- ps auxMultiple workers can multiply memory requirements.
Step 6 — Choose the fix from the evidence
A higher memory limit may be appropriate when the old limit was genuinely undersized. Make resource changes in the workload source of truth, but do not use a larger limit as a substitute for investigating an uncontrolled growth pattern.
Verify
kubectl get pods -n <namespace>
kubectl top pod <pod> -n <namespace> --containersConfirm restart count remains stable and memory stays within an expected range under representative load for longer than the previous failure interval.
Common mistakes
- Assuming every exit 137 is proven OOMKilled without checking Last State/events.
- Looking only at memory after the container restarted.
- Confusing requests with limits.
- Increasing limits repeatedly without investigating growth.