The Linux OOM Killer, Explained
Introduction¶
When Linux can't satisfy a memory allocation and can't reclaim enough, the OOM (out-of-memory) killer picks a process to SIGKILL to free memory. It's a last resort — noisy, blunt, and usually a symptom of a leak or under-provisioning.
How it picks¶
Each process gets an oom_score (0–1000), roughly proportional to its share
of available memory, then adjusted:
cat /proc/<pid>/oom_score # current score
cat /proc/<pid>/oom_score_adj # -1000..+1000, your bias
- Bigger memory footprint → higher score → more likely to be killed.
oom_score_adj = -1000makes a process immune (OOM_SCORE_ADJ_MIN).oom_score_adj = +1000makes it the preferred victim.- The killer avoids killing init, kernel threads, and (if possible) tasks with
oom_score_adjvery negative.
Protect a critical daemon:
# systemd unit
[Service]
OOMScoreAdjust=-800
Or make a batch job the sacrificial one: OOMScoreAdjust=500.
Reading the dmesg dump¶
dmesg -T | grep -A30 -i 'killed process\|out of memory\|oom-kill'
journalctl -k | grep -i oom
You'll see something like:
oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=...,mems_allowed=0,
global_oom,task_memcg=/system.slice/myapp.service,task=python,pid=4242,uid=1000
Out of memory: Killed process 4242 (python) total-vm:8200000kB, anon-rss:7900000kB,
file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:15600kB oom_score_adj:0
Then a task list table (every process with rss, oom_score_adj) — this shows what else was using memory, which is how you find the real hog if the victim was collateral.
constraint=CONSTRAINT_NONE/global_oom→ the whole machine ran out.task_memcg=/system.slice/foo.service+memory cgroup out of memory→ a cgroup limit was hit (systemdMemoryMax, a container limit), not the host. Only that cgroup is affected.
Overcommit¶
sysctl vm.overcommit_memory vm.overcommit_ratio
0(default) — heuristic: allow overcommit unless the request is "obviously" too big.fork()of a large process usually succeeds (COW).1— always overcommit. Needed for e.g. Redis's fork-to-save; risk of the OOM killer firing later.2— strict: never overcommit beyondswap + overcommit_ratio% of RAM.mallocfails early instead of an OOM kill later — cleaner for some workloads, but breaks apps that allocate big and use little.
vm.panic_on_oom=1 makes the box panic (and reboot, with a watchdog) instead of
killing — sometimes preferable for a cluster node.
Prevention¶
- Cap the memory hog in its own cgroup so it's OOM-killed inside its
cgroup, not taking the host down:
MemoryMax=2Gon the unit (see cgroups v2 basics). - Right-size or add swap. A few GB of swap turns a hard OOM into slow
reclaim (and gives you time to react).
zramswap is a good middle ground. - Fix the leak.
smem,ps_mem,/proc/<pid>/smaps_rollup, or a heap profiler. - Set
MemoryHigh(soft) belowMemoryMax— the kernel throttles and reclaims aggressively before the hard kill. earlyoom/systemd-oomd— userspace daemons that act earlier and more gracefully (SIGTERM first, pick by cgroup pressure) than the kernel killer.
Verification and troubleshooting¶
free -h; swapon --show
grep -i oom /var/log/syslog /var/log/messages
systemctl status myapp # "Main process exited, code=killed, status=9/KILL" after an OOM
cat /sys/fs/cgroup/system.slice/myapp.service/memory.events # oom, oom_kill counters
- App "randomly" dies with exit 137 / SIGKILL, no app-level error — OOM kill.
Check
dmesg. 137 = 128 + 9. - OOM killed the wrong process — the victim had the biggest RSS at that
instant. Protect it with
OOMScoreAdjustand cap the actual hog. - No OOM message but processes still dying — a cgroup OOM (check
memory.events), or the app is catching a different signal, or it'ssystemd-oomd(checkjournalctl -u systemd-oomd). vm.overcommit_memory=2broke an app on startup — it allocated a large arena upfront. Either that app needs0/1, or tuneovercommit_ratio.- Box hangs before OOM fires — thrashing on a tiny swap; the killer is slow
to trigger under heavy reclaim.
earlyoom/systemd-oomdhelp; or less swap so it OOMs faster; or (best) more RAM / a memory limit. - Container OOMKilled — the container's memory limit, not the host. Raise the
limit or fix the workload; the runtime reports
OOMKilledseparately from a host OOM.
Related tools and reading¶
- On-site: Linux commands reference.
- Related posts: cgroups v2 basics, Requests vs limits and OOMKilled.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Linux & Sysadmin
resolv.conf and systemd-resolved
On modern distros /etc/resolv.conf points at a stub resolver managed by systemd-resolved. Editing it directly usually does nothing — here's the real model.
October 24, 2026Tuning Open File Limits on Linux
Four different limits control how many files a process can open. 'Too many open files' means you're hitting one specific one — here's how to find and raise it.
October 24, 2026ss and conntrack for Connection Debugging
ss shows you every socket and its send/receive queues; conntrack shows what the firewall is tracking. Together they explain most 'connection refused' and 'no buffer space' problems.
October 24, 2026