What are Memory Overcommit And OOM Killer-Free Embedded Linux Course In Hyderabad

PREV_LEC | NEXT_LEC

Memory Overcommit And OOM Killer

What happens when an embedded board truly runs out of RAM — free linux kernel development course

Every earlier lecture in this free linux kernel development course assumed memory was available to allocate. This lecture covers what happens when it genuinely is not: the kernel’s overcommit policy, the tuning knobs that control it, and the OOM killer — the last line of defense when demand for memory outruns supply.

Keywords covered

overcommit_memory OOM killer oom_score_adj CommitLimit free linux kernel development course

What You Will Learn

  • Why the kernel allows applications to allocate more memory than physically exists
  • The three overcommit policies and when each makes sense on an embedded board
  • How to read CommitLimit and Committed_AS from /proc/meminfo
  • How the OOM killer chooses a victim, and how to influence that choice
  • An original demo that safely triggers and observes overcommit limits

Prerequisites

Root access on a test board or VM you are comfortable rebooting — some of the commands here deliberately push the system toward its memory limits, and should never be run on production hardware.

Why The Kernel Overcommits Memory By Default

The standard Linux memory allocation policy is to over-commit: the kernel lets applications reserve more memory than physically exists. This sounds reckless, but it reflects how real programs behave — most applications ask for more address space than they ever actually touch, and reserving without immediately backing every page keeps allocation fast and cheap. It is also essential for fork(2): forking a large process only needs to share its pages with copy-on-write semantics, not duplicate them in RAM — and since fork is almost always followed by exec, which discards the parent’s memory entirely, most of that “reserved” memory is never even copied.

The Three Overcommit Policies

The policy is controlled by /proc/sys/vm/overcommit_memory:

ValuePolicyBest for
0 (default)Heuristic over-commitGeneral-purpose systems; reasonable default
1Always over-commit, never checkPrograms using large sparse arrays, rare on embedded targets
2Always check, never over-commitMission- or safety-critical embedded systems that must fail predictably

With policy 2, allocations that would exceed the commit limit fail outright instead of succeeding and risking an OOM event later. The commit limit is swap space plus total RAM, multiplied by the overcommit ratio (/proc/sys/vm/overcommit_ratio, default 50%).

Commit Limit Calculation
CommitLimit = (Swap + MemTotal) x (overcommit_ratio / 100) Example: 512 MB RAM, no swap, ratio = 25% CommitLimit = (0 + 512MB) x 0.25 = 128 MB If Committed_AS (memory already promised) exceeds this, overcommit_memory=2 makes ALL further allocations fail – regardless of how much RAM is physically free right now.

Checking Your Board’s Headroom

Two fields in /proc/meminfo tell you exactly where you stand — the enforced ceiling, and how much has already been promised:

# echo 25 > /proc/sys/vm/overcommit_ratio
# grep -e MemTotal -e CommitLimit /proc/meminfo
MemTotal:         509016 kB
CommitLimit:      127252 kB
# grep -e MemTotal -e Committed_AS /proc/meminfo
MemTotal:         509016 kB
Committed_AS:     741364 kB

Here Committed_AS (741 MB promised) already exceeds CommitLimit (127 MB allowed) — under policy 2 this board’s remaining allocations would all fail, regardless of how much RAM is physically free at that instant, until either RAM is added or the number of running processes is reduced.

The OOM Killer

Even with the default heuristic policy, a workload can eventually promise more memory than the system can deliver. At that point there is no polite way out — some process must be killed to free memory. The kernel’s OOM killer computes a heuristic badness score from 0 to 1000 for every process, and terminates the process (or processes) with the highest score until enough memory is free again. A kill shows up in the kernel log like this:

[44510.490320] ep_hogger invoked oom-killer: gfp_mask=0x200da, order=0, oom_score_adj=0
...
Out of memory: Killed process 2113 (ep_hogger) total-vm:524288kB, anon-rss:498212kB

You can influence — or exempt — a specific process from selection by writing an adjustment to /proc/<PID>/oom_score_adj: a value of -1000 means the badness score can never exceed zero, so that process will never be chosen; +1000 guarantees it will always be the top candidate.

Original Demo: Observing Overcommit Safely

This demo, ep_hogger, grows its own memory usage in controlled steps and prints its PID so you can watch /proc/<PID>/oom_score_adj and system memory together — run it only on a disposable VM, never a production board:

/* ep_hogger.c - controlled memory growth for observing overcommit */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define STEP_MB 32

int main(int argc, char *argv[])
{
    int steps = (argc > 1) ? atoi(argv[1]) : 8;
    printf("ep_hogger pid=%d - growing %d MB per step, %d steps\n",
           getpid(), STEP_MB, steps);

    for (int i = 0; i < steps; i++) {
        char *block = malloc(STEP_MB * 1024 * 1024);
        if (!block) {
            printf("step %d: allocation FAILED (overcommit limit hit)\n", i);
            return 1;
        }
        memset(block, 0x33, STEP_MB * 1024 * 1024); /* force residency */
        printf("step %d: now holding roughly %d MB\n", i, (i + 1) * STEP_MB);
        sleep(2);
    }
    printf("ep_hogger finished without hitting a limit\n");
    return 0;
}

Run it under the conservative policy from the earlier example, in a second terminal watch Committed_AS climb:

$ echo 2 > /proc/sys/vm/overcommit_memory
$ echo 25 > /proc/sys/vm/overcommit_ratio
$ ./ep_hogger 20
ep_hogger pid=2551 - growing 32 MB per step, 20 steps
step 0: now holding roughly 32 MB
step 1: now holding roughly 64 MB
...
step 4: allocation FAILED (overcommit limit hit)

Under policy 2 the allocator fails cleanly with ENOMEM once the commit limit is reached — no kill, no crash, exactly the predictable behavior mission-critical embedded software wants. Contrast that with the default heuristic policy (overcommit_memory=0), where the same program is more likely to be allowed to keep allocating until the OOM killer eventually steps in and kills it (or another process) outright.

You can also force an OOM event directly for testing, on a disposable system only:

# echo f > /proc/sysrq-trigger

Overcommit Policy Comparison

PolicyFailure modePredictability
0 (heuristic)OOM killer picks a victim later, possibly not the offending processLow — kill can hit an unrelated process
2 (never overcommit)Allocation itself fails immediately with ENOMEMHigh — the requesting process gets a clear, handleable error

Common Mistakes

  • Assuming free RAM equals allocatable RAM under policy 2 — Committed_AS can already exceed CommitLimit even while RAM shows as “free” at that instant.
  • Setting oom_score_adj=-1000 on everything “important” — if too many processes are exempted, the killer may be forced to pick from an unsuitable remaining pool, or fail to free enough memory at all.
  • Testing overcommit policy 2 changes on production hardware — a too-low overcommit ratio can make legitimate allocations fail unexpectedly across the whole system.

Best Practices

  • On safety- or mission-critical boards, prefer overcommit_memory=2 with a ratio sized from real measured Committed_AS headroom, not a guess.
  • Set oom_score_adj deliberately on your most critical watchdog or supervisor process so it survives an OOM event that kills something less important.
  • Monitor Committed_AS alongside free memory in your on-device logging — it warns you before the OOM killer has to act.

Security Considerations

An unprivileged process that can allocate unbounded memory can effectively deny service to the rest of the board by triggering the OOM killer against unrelated processes. Combine per-process memory limits (cgroups) with a sane overcommit ratio to bound worst-case impact.

Summary And Key Takeaways

Linux overcommits memory by default because most reserved memory is never actually touched, and this keeps common operations like fork() cheap. When commitments genuinely exceed capacity, either the allocator fails predictably (policy 2) or the OOM killer intervenes reactively (policy 0), using a badness score you can influence via oom_score_adj.

Conclusion

Understanding overcommit and the OOM killer closes the loop on memory management for embedded Linux: from measuring usage per process, through catching leaks, to handling the day genuine physical memory runs out. That progression is the backbone of the memory management unit in this free linux kernel development course.

FAQ

What does overcommit_memory=0 do?

It enables the kernel’s default heuristic over-commit policy, allowing most allocations to succeed while relying on the OOM killer if memory genuinely runs out.

What is the safest overcommit setting for safety-critical embedded systems?

overcommit_memory=2, which makes allocations fail predictably with ENOMEM instead of risking a later OOM kill.

How is the commit limit calculated?

CommitLimit equals swap space plus total RAM, multiplied by the overcommit_ratio (default 50%).

How does the OOM killer choose which process to kill?

It computes a heuristic badness score from 0 to 1000 for each process and kills the process with the highest score first.

How can I protect a critical process from the OOM killer?

Write -1000 to /proc/PID/oom_score_adj so its badness score can never exceed zero, exempting it from selection.

Can I force an OOM event for testing?

Yes, echo f to /proc/sysrq-trigger on a disposable test system, never on production hardware.

Does Committed_AS ever exceed CommitLimit under normal operation?

Yes, and once it does under overcommit_memory=2, all further allocations fail until memory is freed or the ratio is raised.

Continue The Free Linux Kernel Development Course

That completes the memory management unit — next up, debugging with GDB.

Next Lecture Course Index
PREV_LEC | NEXT_LEC

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *