Preventing OOM Kills with Linux cgroups v2 memory.high
Stop relying solely on memory.max. Learn how to use Linux cgroups v2 memory.high to throttle memory-intensive processes and prevent OOM kills through proactive reclamation.
01 Oct 2025, 05:09 UTC

The Problem: The Binary Nature of memory.max
When managing memory-intensive applications on Linux, the standard approach is often to set a hard limit using memory.max. While this prevents a single process from consuming all system RAM, it creates a binary outcome: the application either stays under the limit or is immediately terminated by the Out-Of-Memory (OOM) Killer. For many production workloads, a sudden crash is far more disruptive than a temporary slowdown.
The goal is to find a middle ground where the system can pressure a process to reduce its footprint without killing it. This is where memory.high in cgroups v2 becomes a critical engineering tool.
Understanding the Throttle Mechanism
memory.high acts as a proactive reclamation threshold. Unlike memory.max, which is a hard ceiling, memory.high is a "soft" limit that triggers a specific kernel behavior: throttling.
When a process exceeds the memory.high limit, the kernel does not kill the process. Instead, it puts the process into a direct reclaim path. This means the process is forced to spend CPU cycles cleaning up its own memory (reclaiming page caches or swapping) before it is allowed to allocate more. To the application, this manifests as increased latency and decreased throughput, but the process remains alive.
Implementing a Tiered Memory Strategy
A robust resource strategy uses a combination of limits to create a "buffer zone." By setting memory.high below memory.max, you create a window where the application is throttled but not terminated.
| Setting | Behavior | Result of Breach |
|---|---|---|
memory.high |
Proactive Reclamation | Latency increase / Throttling |
memory.max |
Hard Limit | OOM Kill (Process Termination) |
Worked Example: Throttling a Memory-Heavy Task
To use these features, you must be on a system using cgroups v2 (standard in most modern distributions with Kernel 5.x+). You can verify this by checking for the existence of /sys/fs/cgroup/cgroup.controllers.
In this example, we create a cgroup for a background worker and set a throttle limit at 500MB and a hard kill limit at 1GB.
# Run as root or with sudo
# 1. Create a new cgroup directory
mkdir /sys/fs/cgroup/worker_task
# 2. Set the throttle limit (memory.high) to 500MB
echo 500M > /sys/fs/cgroup/worker_task/memory.high
# 3. Set the hard limit (memory.max) to 1GB
echo 1G > /sys/fs/cgroup/worker_task/memory.max
# 4. Move a running process (PID 1234) into this group
echo 1234 > /sys/fs/cgroup/worker_task/cgroup.procs
Verifying the Result
To check if the throttle is actually working, monitor the memory.events file within the cgroup directory. You are looking for the high counter to increment.
# Run this while the process is under load
cat /sys/fs/cgroup/worker_task/memory.events
If the high value is increasing, the kernel is actively throttling the process to keep it under 500MB. If the process continues to grow despite throttling and hits 1GB, dmesg will show the OOM killer terminating the process.
Trade-offs and Limitations
Throttling is not a magic bullet. It relies on the application having reclaimable memory. If the process has allocated a massive amount of "anonymous memory" (heap memory that cannot be evicted to disk or isn't backed by a file), the kernel cannot reclaim it. In such cases, memory.high will fail to stabilize the process, and it will slide quickly toward memory.max and be killed.
Additionally, the latency introduced by direct reclaim can cause timeouts in distributed systems (e.g., a health check failing because the process is too busy reclaiming memory to respond), which might trigger an external orchestrator to restart the container anyway.
Actionable Closing
If your applications are suffering from unpredictable OOM kills, stop relying solely on memory.max. Implement a memory.high limit at roughly 70-80% of your hard limit. This gives your application a chance to stabilize and gives your monitoring systems time to alert you to a memory leak before the process is terminated.
Rollback: To remove these limits, delete the cgroup directory: rmdir /sys/fs/cgroup/worker_task (ensure all processes have been moved out first).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.