Memory Overcommit and Accounting
Linux routinely hands out more virtual memory than it has physical RAM plus swap to back it. This is memory overcommit, and it is the default, deliberate policy — not a bug. The justification is that programs habitually reserve far more address space than they ever touch: a
malloc()of a gigabyte, afork()that duplicates a multi-gigabyte address space via copy-on-write, a sparse array mapped withmmap. Backing every promised page with a real page at allocation time would waste enormous amounts of memory on pages that are never written. Instead the kernel commits lazily: the page-fault handler allocates a physical page only on first touch. Overcommit accounting (vm.overcommit_memory, theCommitted_ASandCommitLimitfields in/proc/meminfo) is the bookkeeping that decides, at allocation time, whether to believe a new promise. When overcommit is on and the promises eventually come due faster than RAM can satisfy them, the OOM killer is the mechanism that pays the debt. This note pins every behavior to the Linux 6.12 and 6.18 long-term-support (LTS) kernels.
Mental Model — Promises vs. Pages
Think of physical memory as a bank and each mmap/brk/fork as a line of credit, not a withdrawal. The kernel tracks the total credit it has extended (Committed_AS) and, in the strict mode, refuses to extend more than a ceiling (CommitLimit). Most of the time the credit is never fully drawn — which is exactly why the bank can safely promise more than it holds. Overcommit policy is the bank’s lending strategy.
flowchart TB REQ["Process requests address space<br/>mmap / brk / fork / mremap"] REQ --> MODE{vm.overcommit_memory} MODE -->|"1 = ALWAYS"| OK1["Always succeed<br/>(no accounting check)"] MODE -->|"0 = GUESS (default)"| GUESS{"request ><br/>RAM + swap?"} GUESS -->|no| OK0["Succeed"] GUESS -->|"yes (wild alloc)"| FAIL0["-ENOMEM"] MODE -->|"2 = NEVER"| LIMIT{"Committed_AS + req<br/>> CommitLimit?"} LIMIT -->|no| OK2["Succeed, charge Committed_AS"] LIMIT -->|yes| FAIL2["-ENOMEM (early, no OOM)"] OK0 --> TOUCH["Pages faulted in on first touch<br/>(demand paging)"] OK1 --> TOUCH OK2 --> TOUCH TOUCH -->|"RAM exhausted under modes 0/1"| OOM["OOM killer fires"]
The three overcommit modes and where the bill comes due. What it shows: mode 1 (always) skips accounting entirely; mode 0 (the default heuristic) only rejects a single allocation larger than all RAM+swap; mode 2 (never) enforces a hard CommitLimit and fails allocations early with -ENOMEM rather than risk an OOM kill later. The insight to take: modes 0 and 1 push the failure to fault time (where the only recourse is the OOM killer), while mode 2 pushes it to allocation time (where the program gets a clean error it can handle). Overcommit is the choice between optimistic lazy backing and pessimistic up-front guarantees.
Why Linux Overcommits
The case for overcommit is empirical: real workloads over-reserve. Several common patterns make eager backing wasteful or impossible:
mallocover-allocation.glibc’s allocator grows the heap withbrk(2)/sbrk(2)and serves allocations larger thanMMAP_THRESHOLD(128 KB by default) with a private anonymousmmap(2)(malloc(3)); it requests memory from the kernel in chunks and parcels it out, so most programs reserve more than they ever free or touch.fork()and copy-on-write.fork()conceptually duplicates the parent’s entire address space, but the kernel marks the pages read-only and shares them; a private copy is made only on write. A 4 GiB process that forks and immediatelyexecs a tiny program would, under eager accounting, momentarily “owe” 8 GiB it never uses. The overcommit-accounting doc captures this rule precisely: aPRIVATE WRITABLEanonymous mapping costs “size of mapping per instance,” but read-only and shared file mappings cost 0 because the file is the backing store (overcommit-accounting.rst, v6.12).- Sparse data structures. Scientific code mapping a huge sparse array relies on the “virtual memory consisting almost entirely of zero pages” — the kernel doc names this as the motivating use case for mode 1 (
overcommit-accounting.rst).
Backing all of that eagerly would force you to provision RAM+swap for the sum of all promises rather than the peak of all touches, typically a multiple more memory for no benefit. Overcommit trades a small tail risk (running out of physical memory and invoking the OOM killer) for a large, constant memory saving.
The Three Modes — vm.overcommit_memory
The policy is selected by the sysctl vm.overcommit_memory, an integer 0/1/2. The authoritative description is the kernel’s own overcommit doc (overcommit-accounting.rst, v6.12):
0 — Heuristic overcommit handling. Obvious overcommits of address space are refused. Used for a typical system. … This is the default. 1 — Always overcommit. Appropriate for some scientific applications. … 2 — Don’t overcommit. The total address space commit for the system is not permitted to exceed swap + a configurable amount (default is 50%) of physical RAM.
All three live in one decision function, __vm_enough_memory() in mm/util.c, called on every accounted allocation. Here it is verbatim (mm/util.c, v6.12):
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
{
long allowed;
unsigned long bytes_failed;
vm_acct_memory(pages);
/*
* Sometimes we want to use more memory than we have
*/
if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
return 0;
if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
if (pages > totalram_pages() + total_swap_pages)
goto error;
return 0;
}
allowed = vm_commit_limit();
/*
* Reserve some for root
*/
if (!cap_sys_admin)
allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
/*
* Don't let a single process grow so big a user can't recover
*/
if (mm) {
long reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
allowed -= min_t(long, mm->total_vm / 32, reserve);
}
if (percpu_counter_read_positive(&vm_committed_as) < allowed)
return 0;
error:
bytes_failed = pages << PAGE_SHIFT;
pr_warn_ratelimited("%s: pid: %d, comm: %s, bytes: %lu not enough memory for the allocation\n",
__func__, current->pid, current->comm, bytes_failed);
vm_unacct_memory(pages);
return -ENOMEM;
}Reading the three branches:
-
OVERCOMMIT_ALWAYS(mode 1) returns0(success) unconditionally after charging the accounting counter viavm_acct_memory(pages). No limit is consulted; the allocation always succeeds. The only way to fail is to physically run out of pages at fault time, which then summons the OOM killer. -
OVERCOMMIT_GUESS(mode 0, the default) is the heuristic, and it is far simpler than its name suggests: it fails only if a single allocation request (pages) exceeds all of RAM plus swap (totalram_pages() + total_swap_pages). Anything smaller succeeds. This is the literal meaning of the doc’s “obvious overcommits… refused” andvm.rst’s “rejects obvious overcommits” (vm.rst, v6.12): mode 0 catches only the catastrophically-wild single allocation (a corrupted size, an accidental1 << 60), and lets all normal over-reservation through. It does not track cumulative commitment against a ceiling — that is mode 2’s job. Two independent primary sources (the prose doc and the code) agree on exactly this, so it is not a “guess” in the sense of being fuzzy; it is a deliberately permissive single-allocation sanity check. -
OVERCOMMIT_NEVER(mode 2) is the only mode that enforces a cumulative ceiling. It computesallowed = vm_commit_limit()(theCommitLimit, below), subtracts two reserves, and refuses the allocation if the system’s running total of committed address space (vm_committed_as) plus the new request would exceedallowed. On refusal it logs a rate-limited warning, un-accounts the pages, and returns-ENOMEM— a clean error the calling program sees as a failedmmap/brk. Crucially this happens at allocation time, so a well-written program can handle it; there is no later OOM surprise (in the common case).The two reserves protect against pathological exhaustion:
sysctl_admin_reserve_kbytes(vm.admin_reserve_kbytes) is withheld from non-privileged callers (!cap_sys_admin) so that a root recovery shell can still allocate after userspace has filled memory.sysctl_user_reserve_kbytes(vm.user_reserve_kbytes), capped atmm->total_vm / 32, keeps a single runaway process from consuming so much that the user cannot even runkillto recover.
In the v6.18 LTS source, __vm_enough_memory() and the mode constants are unchanged in behavior, and the default remains OVERCOMMIT_GUESS (int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS; in mm/util.c, v6.18). Everything in this section holds for both LTS branches as of 2026.
CommitLimit — How the Ceiling Is Computed
CommitLimit is the mode-2 ceiling, computed by vm_commit_limit() (mm/util.c, v6.12):
unsigned long vm_commit_limit(void)
{
unsigned long allowed;
if (sysctl_overcommit_kbytes)
allowed = sysctl_overcommit_kbytes >> (PAGE_SHIFT - 10);
else
allowed = ((totalram_pages() - hugetlb_total_pages())
* sysctl_overcommit_ratio / 100);
allowed += total_swap_pages;
return allowed;
}The ceiling is therefore swap + a slice of RAM, where the slice is specified one of two mutually-exclusive ways:
vm.overcommit_kbytes— an absolute amount of RAM, in kibibytes (converted to pages by>> (PAGE_SHIFT - 10), i.e. divide by 4 since a page is 4 KiB = 2^2 KiB). If set non-zero, it wins.vm.overcommit_ratio— a percentage of physical RAM (minus huge-page reservations, which are managed separately by hugetlbfs). The default is 50, matching the doc’s “default is 50%”. So on a 32 GiB machine with no swap, the defaultCommitLimitis 16 GiB.
These two are counterparts: setting one zeroes the other (reading the inactive one returns 0), as vm.rst notes (vm.rst, v6.12). Both overcommit_ratio and overcommit_kbytes only take effect in mode 2 — in modes 0 and 1 they are computed and displayed but never consulted by the allocation path.
Reading the State — /proc/meminfo
Two /proc/meminfo fields expose the accounting, emitted by fs/proc/meminfo.c (v6.12):
committed = vm_memory_committed();
...
show_val_kb(m, "CommitLimit: ", vm_commit_limit());
show_val_kb(m, "Committed_AS: ", committed);CommitLimitis exactlyvm_commit_limit()rendered in kibibytes — the mode-2 ceiling. It is shown regardless of mode, which is the single most common source of confusion: seeing aCommitLimitdoes not mean the system is enforcing it. In the default mode 0,CommitLimitis purely informational. It is the threshold that would apply if you switched to mode 2.Committed_AS(“committed address space”) is the running totalvm_committed_as— the sum of all memory the kernel has promised to back, across every process, computed by the accounting rules inovercommit-accounting.rst(private-writable anonymous = full size, shared/read-only file = 0, and so on). WhenCommitted_ASexceedsCommitLimit, the system is overcommitted — fine in modes 0/1, impossible in mode 2.
A worked example: on a host showing MemTotal: 16 GiB, SwapTotal: 4 GiB, default overcommit_ratio = 50, the CommitLimit is 0.5 × 16 + 4 = 12 GiB. A Committed_AS of 20 GiB means programs have reserved 20 GiB of address space — perfectly normal under mode 0 because most of it is untouched COW or sparse mapping; switching to mode 2 at this point would immediately start failing new mallocs.
The Relationship to the OOM Killer
Overcommit and the OOM killer are two ends of the same policy. The connection is causal:
- Under modes 0 and 1, the kernel deliberately promises more than it can back. As long as processes don’t touch all their promises, physical RAM suffices. But when collective resident usage (the pages actually faulted in via demand paging) outgrows RAM + swap, the kernel cannot satisfy a fault and cannot fail it — the page fault is not a system call that can return
-ENOMEMto the program. Its only recourse is to free memory by killing a process, which is precisely what the OOM killer does, selecting a victim via the [[OOM Score and Victim Selection|oom_badness()heuristic]]. Overcommit is why the OOM killer must exist: lazy commitment defers the accounting failure to fault time, where the only lever left is termination. - Under mode 2, the kernel refuses to overcommit, so the failure surfaces early — at the
mmap/brkthat would pushCommitted_ASoverCommitLimit, returning-ENOMEM. A program that checks its allocation return values can degrade gracefully. The OOM killer should rarely or never fire (barring kernel allocations and edge cases). Mode 2 trades the OOM killer’s surprise for up-front allocation failures the application must be written to handle.
This is the central trade-off: modes 0/1 optimize memory utilization and accept tail OOM-kill risk; mode 2 sacrifices utilization for predictable, handleable allocation failures. Databases and latency-critical services that cannot tolerate a kill sometimes run mode 2 with generous CommitLimit; general-purpose systems run the default mode 0.
Configuration Examples
# Inspect current policy and accounting
sysctl vm.overcommit_memory # 0, 1, or 2
grep -E 'CommitLimit|Committed_AS' /proc/meminfo
# Mode 1: always overcommit (e.g. for a Redis box that forks for RDB snapshots)
sysctl -w vm.overcommit_memory=1 # avoids fork() failing when the child is short-lived
# Mode 2: strict, ceiling = swap + 80% of RAM
sysctl -w vm.overcommit_memory=2
sysctl -w vm.overcommit_ratio=80 # percentage form
# OR an absolute ceiling instead of a percentage:
sysctl -w vm.overcommit_kbytes=8388608 # 8 GiB of RAM (+ swap); zeroes overcommit_ratioThe Redis case (line 8) is a classic real-world mode-1 use. Redis fork()s to write a background snapshot, and the child shares the parent’s heap via COW, touching almost none of the inherited pages. Redis’s documentation explicitly instructs operators to “Set the Linux kernel overcommit memory setting to 1. Add vm.overcommit_memory = 1 to /etc/sysctl.conf” precisely to avoid “Background saving fails with a fork() error on Linux” (Redis administration docs). Note the mechanism: fork() does run the overcommit check — dup_mmap() in kernel/fork.c calls security_vm_enough_memory_mm() (→ __vm_enough_memory()) for each accountable (VM_ACCOUNT) VMA, charging the mapping’s length (kernel/fork.c, v6.12). Under the default mode 0, that charge is rejected only if a single VMA’s length exceeds RAM+swap, so a normal Redis instance’s fork is not blocked by mode 0; the documented fork-failure regime is mode 2 (strict accounting), where charging the child’s full private-writable footprint can push Committed_AS over CommitLimit. Setting mode 1 sidesteps the check entirely and is the simplest fix regardless of which mode caused the failure.
Failure Modes and Common Misunderstandings
- “
CommitLimitis enforced.” Only in mode 2. The default mode 0 displays it but ignores it. Many a confused operator has seenCommitted_ASexceedCommitLimitand assumed a bug. - “
Committed_ASis how much RAM is in use.” No — it is how much address space has been promised, including untouched COW pages, sparse mappings, and reserved-but-unfaulted anonymous memory. Actual resident usage isMemTotal - MemAvailable(roughly).Committed_ASroutinely far exceeds real usage under overcommit, and that gap is the point. MAP_NORESERVEis ignored in mode 2. Normallymmap(..., MAP_NORESERVE)asks the kernel to skip overcommit accounting for that mapping; the doc notes that in mode 2 this flag is ignored (overcommit-accounting.rst), so even “no-reserve” mappings count against the limit.- Stack growth corner case. The doc warns that C stack growth does an implicit
mremap, so a program running near the mode-2 ceiling that wants absolute guarantees “MUSTmmapyour stack for the largest size you think you will need” — otherwise a deep call chain can hit-ENOMEMmid-execution (overcommit-accounting.rst). - The accounting doc’s “To Do: implement actual limit enforcement.” The
overcommit-accounting.rst“Status”/“To Do” lists are historical and partly stale (they predate the modern enforcement in__vm_enough_memory); read the rules sections as current and the status checklist as legacy context.
Alternatives and When to Choose Them
- Default (mode 0) for nearly all general-purpose systems: maximum memory efficiency, OOM killer as the safety net. Pair with sensible [[OOM Score and Victim Selection|
oom_score_adj]] values to protect critical services. - Mode 1 for workloads that legitimately reserve vast sparse/COW memory they won’t touch (scientific sparse arrays, fork-heavy services like Redis snapshotting). Accepts that the OOM killer is the only backstop.
- Mode 2 for systems that must never be surprised by a kill and whose applications check allocation returns — at the cost of stranding RAM you’ve reserved against the limit. Tune
overcommit_ratio/overcommit_kbyteswith swap in mind, since both addtotal_swap_pages. - Per-cgroup limits (memcg
memory.max/memory.high) are a different and complementary mechanism: they bound resident usage per group and trigger per-cgroup reclaim and OOM, rather than bounding system-wide committed address space. Containerized systems usually rely on memcg, not global mode 2.
See Also
- The OOM Killer — the consequence of modes 0/1: when committed promises come due faster than RAM can satisfy them, the OOM killer terminates a process to recover memory.
- OOM Score and Victim Selection — which process the OOM killer picks; its
oom_badness()score reflects resident reality, the flip side of the committed promises this note accounts for. - Copy-on-Write and fork — the canonical reason overcommit pays off:
fork()duplicates an address space cheaply because shared pages are charged at “size per instance” only when written. - Demand Paging — the mechanism that defers physical backing to first touch, making lazy commitment possible.
- Memory Reclaim Overview — the kernel’s first response to pressure, tried before the OOM killer; mode 2 aims to avoid reaching either.
- MOC: Linux Memory Management MOC (§1, Virtual Memory and the Process Address Space; cross-cuts §11, the OOM killer).