Tuning vm.overcommit_memory shifts the failure point from a blind heuristic back to your own budget, which changes exactly who eats an OOM kill.
Why malloc rarely fails
vm.overcommit_memory defaults to 0, the heuristic mode that says yes to almost every mmap and malloc while it can plausibly honor them, and only refuses when the system is genuinely short on memory. Committing virtual memory costs almost nothing up front because pages are handed out lazily, so most allocations succeed and most normal applications stay alive at near-zero cost. The price of the generosity is that the kernel can over-commit far beyond RAM, betting that you will not touch every page; when many bytes actually get written, someone has to pay with an OOM kill.
The knob
vm.overcommit_memory lets you choose who holds the budget. The default 0 is heuristic overcommit: the kernel refuses only obviously impossible requests and otherwise says yes, trusting most processes never touch every byte they reserve. Setting it to 1 means always overcommit: almost any allocation is granted, which suits huge sparse mappings that stay mostly untouched, but every failure is pushed downstream to reclaim or the OOM killer. Setting it to 2 means strict accounting: any allocation beyond CommitLimit, roughly swap plus overcommit_ratio percent of RAM (overcommit_kbytes takes over when nonzero), fails with ENOMEM at request time. Neither extreme is free: always-overcommit hides pressure until the machine stalls, and strict mode breaks programs that reserve generously but touch little.
Heuristic versus strict
The real choice is who pays when the reckoning arrives. In heuristic mode the kernel keeps over-committing and, under pressure, picks a victim to kill; in strict mode the boundary is drawn in advance, so the failure surfaces at malloc time and the operator, not the scheduler, decides which process eats an OOM kill. Containers and VMs typically set a controlled value because a host over-committing on behalf of many guests can collapse when their aggregate demand spikes. A laptop can be generous; a production box that must not silently lose a worker should be explicit about its budget.
When it breaks
Under the default heuristic mode, the most confusing failure is a large malloc or mmap that returns success and then dies later. No pages were touched yet, so the allocation looked fine; once the process writes into them and memory runs short, the OOM killer picks a victim, often not the over-allocator but the largest nearby process. The log shows Out of memory: Killed process with no failed allocation in sight, so teams chase the wrong binary while the real over-reservation stays hidden.
Mode 1, always overcommit, fails slower. Absurd reservations are granted without protest, pressure builds silently, and a machine with swap slides into a swap storm where everything is alive but nothing progresses. Latency collapses before any kill frees memory, sessions stall, and the eventual OOM kill looks random because too many processes hold promises the system could never keep together.
Mode 2, strict accounting, fails at request time instead. A JVM reserving a large heap up front, or a fork-heavy service briefly needing twice its resident set accounted, gets ENOMEM at startup even though it would never touch every page. Operators who copy a strict overcommit_ratio from a swapless laptop onto a database host watch healthy programs refuse to start; size the ratio against the gap between CommitLimit and Committed_AS in /proc/meminfo instead of flipping the mode blindly.
Check it quickly
Save the following as overcommit_probe.py and run python3 overcommit_probe.py. It uses only the standard library, opens the overcommit_* knobs and /proc/meminfo read-only, changes nothing, and needs no privileges. Without those proc files it prints SKIP instead of failing.
"""Read-only overcommit audit: report mode, budget, and pressure."""
from pathlib import Path
def read_value(path):
try:
return Path(path).read_text(encoding="utf-8").strip()
except FileNotFoundError:
return None
except OSError as exc:
return "UNREADABLE: %s" % exc
def meminfo_kb(text):
fields = {}
for line in text.splitlines():
name, _, rest = line.partition(":")
digits = "".join(ch for ch in rest if ch.isdigit())
if name and digits:
fields[name.strip()] = int(digits)
return fields
def main():
mode = read_value("/proc/sys/vm/overcommit_memory")
ratio = read_value("/proc/sys/vm/overcommit_ratio")
kbytes = read_value("/proc/sys/vm/overcommit_kbytes")
meminfo = read_value("/proc/meminfo")
if mode is None or meminfo is None:
print("SKIP: /proc/sys/vm/overcommit_memory or /proc/meminfo missing (non-Linux?)")
return
info = meminfo_kb(meminfo)
print("overcommit_memory=%s overcommit_ratio=%s overcommit_kbytes=%s" % (mode, ratio, kbytes))
print("MemTotal=%s kB SwapTotal=%s kB CommitLimit=%s kB Committed_AS=%s kB" % (
info.get("MemTotal", "?"), info.get("SwapTotal", "?"),
info.get("CommitLimit", "?"), info.get("Committed_AS", "?"),
))
names = {"0": "heuristic", "1": "always overcommit", "2": "strict accounting"}
print("mode means: %s" % names.get(mode, "unknown value"))
limit = info.get("CommitLimit")
committed = info.get("Committed_AS")
if mode == "0":
print("suggestion: heuristic default; watch Committed_AS growth, prefer mode 2 for workers that must not be OOM-killed")
elif mode == "1":
print("suggestion: always overcommit; expect swap storms under pressure, prefer 0 or 2 unless sparse mappings need it")
elif mode == "2" and limit and committed:
headroom = limit - committed
print("commit headroom=%s kB; suggestion: enlarge ratio/kbytes if headroom is small, shrink them if headroom is huge" % headroom)
else:
print("suggestion: unexpected mode value; compare Committed_AS against CommitLimit before changing anything")
if __name__ == "__main__":
main()
On a default workstation the script reports overcommit_memory=0 and names it heuristic. Under mode 2, compare the headroom: Committed_AS near CommitLimit explains startup ENOMEM, while huge headroom means the ratio is merely conservative. Under mode 1 the suggestion warns about swap storms, matching the slow-then-random failure above.
Further reading
Sources
- Kernel vm sysctl documentation, defines the overcommit_memory modes and defaults, checked 2026-06-01.
- proc manual page, documents /proc/meminfo CommitLimit and Committed_AS accounting, checked 2026-06-01.