What is the 'Cannot allocate memory' Error in Linux?
The Cannot allocate memory error (often appearing as ENOMEM or errno 12) is a system-level failure that occurs when a process requests memory from the operating system and the kernel refuses because it cannot satisfy the request. This is not the same as an application-level OutOfMemoryError — it is a lower-level failure returned by system calls like fork(), mmap(), brk(), or malloc() when the kernel's memory management subsystem determines that no virtual memory can be granted to the calling process.
You may encounter this error in various forms across your production logs:
- Shell/CLI:
bash: fork: Cannot allocate memory - Application logs:
OS error: Cannot allocate memoryorerrno=12 - System logs:
kernel: __alloc_pages_nodemask: allocation failurein dmesg - Container runtimes:
runc: runc create failed: Cannot allocate memory - Database engines:
FATAL: could not allocate memory for shared memory
Critically, this error can occur even when free -m shows available RAM. The root cause is rarely a simple case of exhausting all physical memory — it is usually tied to virtual memory limits, process limits, memory fragmentation, or kernel-enforced constraints.
Why It Matters in Production
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →In production environments, this error is particularly dangerous because it is often silent until it becomes catastrophic. A single Cannot allocate memory failure can cascade:
- Daemon crashes: Monitoring agents, SSH daemons, or cron jobs fail to fork, leaving systems unreachable
- Database corruption: Postgres or MySQL fail to allocate shared buffers mid-transaction
- Orchestrator failures: Kubernetes pods enter
ErrororCrashLoopBackOffstates because the kubelet cannot spawn new containers - Incomplete deployments: CI/CD pipelines hang because
git,npm, ordocker buildcannot fork subprocesses - Loss of remote access: SSH daemon fails on
fork(), locking operators out of the machine entirely
Unlike a straightforward OOM kill (where the kernel selects a victim process and terminates it), ENOMEM on fork or allocation often leaves the system in a zombie-like state: existing processes may continue running, but no new processes can be created. This is the classic "fork bomb" symptom — the machine is alive but entirely unresponsive to new work.
Root Cause Analysis: Identifying the Real Culprit
Root cause analysis for Cannot allocate memory requires peeling back multiple layers. The error message alone tells you that an allocation failed, but not why. You must systematically investigate the following potential causes, in order of likelihood in production environments:
1. Process / Thread Limits (ulimit / cgroup)
The single most common cause in modern production systems — especially containerized ones — is hitting a limit on the number of processes or threads, not a lack of raw memory. The fork() system call requires the kernel to allocate a new process control block (PCB), stack, and memory mappings. If the process count limit is reached, fork() fails with EAGAIN or ENOMEM even when gigabytes of RAM are free.
Check the current limits for a running process (replace <PID> with the process ID):
# Check limits of a specific process
cat /proc/<PID>/limits
# Example output:
# Max processes 4096 4096 processes
# Max open files 1024 4096 files
For system-wide limits, inspect:
# Current system-wide max PID
cat /proc/sys/kernel/pid_max
# Current number of processes
ps aux | wc -l
# Or more precisely, count tasks
cat /proc/loadavg # Last field is running/total tasks
ls /proc | grep '^[0-9]' | wc -l
In containerized environments (Docker, Kubernetes, LXC), cgroup limits are the controlling factor. Inspect them with:
# For a container with cgroup v1
cat /sys/fs/cgroup/pids/docker/<container_id>/pids.max
cat /sys/fs/cgroup/pids/docker/<container_id>/pids.current
# For cgroup v2
cat /sys/fs/cgroup/system.slice/docker-<container_id>.scope/pids.max
cat /sys/fs/cgroup/system.slice/docker-<container_id>.scope/pids.current
If pids.current equals pids.max, no new process can be forked inside that container — and you'll get Cannot allocate memory on any fork attempt, regardless of available RAM.
2. Memory Overcommit Policy and Virtual Memory Exhaustion
Linux uses a virtual memory overcommit system controlled by vm.overcommit_memory and vm.overcommit_ratio. The kernel can promise more virtual memory to processes than physically exists, relying on the fact that processes rarely use all they request. However, when overcommit is disabled or the limit is reached, allocations fail.
# Check overcommit settings
cat /proc/sys/vm/overcommit_memory
cat /proc/sys/vm/overcommit_ratio
# 0 = heuristic overcommit (default)
# 1 = always overcommit
# 2 = strict overcommit (never commit more than ratio% of RAM + swap)
To see current virtual memory commitment:
# Check committed virtual memory vs physical RAM + swap
cat /proc/meminfo | grep -E 'CommitLimit|Committed_AS'
# Example output:
# CommitLimit: 12345678 kB
# Committed_AS: 12345000 kB <-- close to limit!
When Committed_AS approaches CommitLimit and overcommit_memory=2, the kernel will reject further mmap() or brk() calls with ENOMEM. This is common on systems with large databases or JVM applications that pre-allocate huge heaps via mmap.
3. System-wide Memory Saturation and the OOM Killer
Sometimes the error appears just before the OOM killer activates, or on systems where OOM killer is disabled or tuned to be less aggressive. Check kernel logs for allocation failures:
# Look for kernel-level allocation failures
dmesg -T | grep -i 'allocation failure\|out of memory\|OOM'
journalctl -k | grep -i 'alloc_pages\|out of memory'
# Check current memory pressure
cat /proc/meminfo
free -h
Key fields in /proc/meminfo to watch:
grep -E '^(MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|Unevictable)' /proc/meminfo
If MemAvailable is near zero and swap is exhausted, the system is truly out of memory. But remember: MemFree being low is normal on Linux due to cache — always look at MemAvailable which accounts for reclaimable cache.
4. Memory Fragmentation and HugePages
Memory fragmentation occurs when the kernel has plenty of free memory, but cannot find a contiguous block of the requested size (order). This is especially common on long-running systems with heavy network I/O or systems using HugePages. The kernel log will reveal the allocation order that failed:
# Check kernel ring buffer for page allocation failures
dmesg | grep -E 'order:|alloc_pages'
# Example: "alloc_pages: order:4 failed" means kernel needed
# 2^4 = 16 contiguous pages (64KB on x86_64) but couldn't find them
Check current fragmentation:
# View buddy allocator fragmentation
cat /proc/buddyinfo
# Example: Node 0, zone Normal ... 438 217 89 34 12 5 2 1 0 0 1
# Each column is a power-of-2 page block count. Many zeros in higher
# orders = severe fragmentation
Also check HugePages configuration, as reserved but unused HugePages reduce available general-purpose memory:
cat /proc/sys/vm/nr_hugepages
cat /proc/meminfo | grep -i huge
5. Per-process Virtual Memory Limit (vm.max_map_count, RLIMIT_AS)
Even when system memory is abundant, a single process can hit its own virtual memory limits:
# Check address space limit for a process
cat /proc/<PID>/limits | grep 'Max address space'
# Check max memory map regions (important for JVM, Elasticsearch, Redis)
cat /proc/sys/vm/max_map_count
cat /proc/<PID>/maps | wc -l # current map count for the process
If a process exceeds vm.max_map_count (default 65530), mmap() calls fail with ENOMEM. This is a notorious issue with Elasticsearch and MongoDB workloads that use many memory-mapped files.
6. Kernel Memory Leaks or Slab Cache Bloat
Kernel memory leaks (in drivers, filesystems, or kernel modules) can consume memory that free does not account for in userspace. The slab allocator caches kernel objects; excessive slab usage can starve userspace allocations:
# Check slab cache usage
cat /proc/meminfo | grep -E 'SReclaimable|SUnreclaim|Slab'
slabtop -s c # sort by cache size, interactive
# Or snapshot:
slabtop -s c -o | head -30
If SUnreclaim (unreclaimable slab memory) grows continuously over days, you may have a kernel memory leak. This requires deeper investigation with slabtop and potentially kernel debugging.
How to Fix It: Immediate and Long-term Remediation
Once you've identified the root cause through the analysis above, apply the appropriate fix. Below are concrete remediation steps organized by root cause category.
Fix 1: Increase Process Limits (ulimit / cgroup)
For a running process (temporary, as root):
# Set max processes for a bash session
ulimit -u 8192
# Or for a specific process using prlimit (Linux)
prlimit --pid <PID> --nproc=8192:8192
Permanent system-wide via /etc/security/limits.conf:
# Add to /etc/security/limits.conf
* soft nproc 8192
* hard nproc 16384
root soft nproc unlimited
root hard nproc unlimited
For systemd services, set limits in the unit file:
# In /etc/systemd/system/myservice.service
[Service]
LimitNPROC=8192
LimitNOFILE=65536
For Docker containers at runtime:
# Increase pids limit when running container
docker run --pids-limit 1024 --memory 2g myimage
# In docker-compose.yml
services:
myapp:
pids_limit: 1024
mem_limit: 2g
For Kubernetes pods:
# In pod spec or deployment template
spec:
containers:
- name: myapp
resources:
limits:
memory: "2Gi"
requests:
memory: "1Gi"
# Note: Kubernetes does not have a direct pids limit field in older versions
# Use --pids-limit on the containerd/runc level or set via node allocatable
For Kubernetes nodes, ensure kubelet reserve allows enough PID space:
# kubelet configuration
# --pod-max-pids or --max-pods combined with system reserved pids
Fix 2: Tune Memory Overcommit
For most production workloads, the default heuristic overcommit (overcommit_memory=1 or 0) works well. If you are on strict mode (2) and hitting limits:
# Temporarily switch to heuristic overcommit
echo 0 > /proc/sys/vm/overcommit_memory
# Or always overcommit (use with caution)
echo 1 > /proc/sys/vm/overcommit_memory
# Permanent via sysctl
echo "vm.overcommit_memory = 0" >> /etc/sysctl.conf
sysctl -p
If you must stay on strict mode, increase the ratio:
# Set overcommit ratio to 90% of RAM (default is 50)
echo 90 > /proc/sys/vm/overcommit_ratio
echo "vm.overcommit_ratio = 90" >> /etc/sysctl.conf
Fix 3: Free Memory and Manage OOM
When memory is genuinely exhausted, you need to free it or add capacity:
# Drop page cache (non-destructive, cache will rebuild)
echo 3 > /proc/sys/vm/drop_caches
sync; echo 3 > /proc/sys/vm/drop_caches
# Identify memory hogs
ps aux --sort=-%mem | head -20
# For containers, check cgroup memory usage
cat /sys/fs/cgroup/memory/docker/<container_id>/memory.usage_in_bytes
Enable and tune the OOM killer to be more responsive:
# Make OOM killer more aggressive (lower score for important processes)
# Adjust oom_score_adj for critical processes to -1000 (unkillable)
echo -1000 > /proc/<PID>/oom_score_adj
# Check current oom_score (higher = more likely to be killed)
cat /proc/<PID>/oom_score
For systemd services, configure OOM protection:
# In service unit file
[Service]
OOMScoreAdjust=-900
Fix 4: Resolve Memory Fragmentation
Fragmentation requires proactive measures:
# Compact memory (requires kernel 3.10+)
echo 1 > /proc/sys/vm/compact_memory
# Defragment via page migration
echo 3 > /proc/sys/vm/drop_caches # first, drop caches
echo 1 > /proc/sys/vm/compact_memory
# Tune vm.min_free_kbytes to keep a reserve pool for high-order allocations
echo 131072 > /proc/sys/vm/min_free_kbytes # 128MB reserve
echo "vm.min_free_kbytes = 131072" >> /etc/sysctl.conf
Reduce HugePages if they are over-allocated:
# Check current HugePages
cat /proc/sys/vm/nr_hugepages
# Reduce to zero if not needed
echo 0 > /proc/sys/vm/nr_hugepages
echo "vm.nr_hugepages = 0" >> /etc/sysctl.conf
Fix 5: Increase vm.max_map_count
For workloads like Elasticsearch, Kafka, or MongoDB that use many mmap regions:
# Check current limit
cat /proc/sys/vm/max_map_count
# Increase significantly (262144 is common for ES)
echo 262144 > /proc/sys/vm/max_map_count
echo "vm.max_map_count = 262144" >> /etc/sysctl.conf
sysctl -p
For Docker, ensure this is set on the host — containers inherit the host kernel's max_map_count.
Fix 6: Kernel Slab / Memory Leak Mitigation
If slab memory is bloated, you can drop reclaimable slab caches:
# Drop reclaimable slab (dentries, inodes)
echo 2 > /proc/sys/vm/drop_caches
sync; echo 2 > /proc/sys/vm/drop_caches
For persistent kernel leaks, you may need to identify the leaking module and reload it:
# Check top slab consumers
slabtop -s c -o | head -20
# If a specific module (e.g., a filesystem driver) is leaking,
# you may need to unmount filesystems, rmmod the module, and reload
# This is complex and may require a maintenance window
In extreme cases, a scheduled reboot is the most reliable remediation while you work with kernel vendors on a permanent fix.
Best Practices for Prevention
Preventing Cannot allocate memory errors in production requires a defense-in-depth approach. Implement these practices across your infrastructure:
- Monitor process counts as diligently as memory usage. Set alerts on
pids.current/pids.maxratio in cgroups and on total system process count approachingpid_max. - Set generous but bounded ulimits in service definitions, Dockerfiles, and systemd units. Never rely on defaults (often 4096 or lower) for production services.
- Configure OOM protection for critical infrastructure daemons (SSH, monitoring agents, kubelet, containerd) with
oom_score_adj = -900or lower so they survive memory storms. - Use memory + swap accounting in cgroups to catch containers leaking memory before they affect the host.
- Set vm.min_free_kbytes to a reasonable value (e.g., 128MB–256MB on servers with 64GB+ RAM) to maintain a reserve for high-order allocations and prevent fragmentation-induced allocation failures.
- Regularly test your monitoring by simulating memory pressure with
stress-ngorsysbenchto verify alerts fire correctly. - Log all ENOMEM occurrences at the application layer with stack traces and context (what operation was attempted, what limits were in effect at the time).
- Pre-allocate and pin critical processes early in boot or container startup to ensure they get their memory before the system becomes fragmented.
Debugging Script for Quick Diagnosis
Below is a diagnostic script you can run on a problematic production host (requires root or appropriate capabilities) to quickly surface the most likely root cause. This script is safe to run and does not modify any system state:
#!/bin/bash
# diagnose_enomem.sh - Quick root cause analysis for 'Cannot allocate memory'
# Run as: sudo bash diagnose_enomem.sh
echo "=== SYSTEM MEMORY OVERVIEW ==="
free -h
echo ""
echo "=== VIRTUAL MEMORY COMMITMENT ==="
grep -E 'CommitLimit|Committed_AS' /proc/meminfo
echo ""
echo "=== OVERCOMMIT POLICY ==="
echo "overcommit_memory: $(cat /proc/sys/vm/overcommit_memory)"
echo "overcommit_ratio: $(cat /proc/sys/vm/overcommit_ratio)%"
echo ""
echo "=== PROCESS COUNT LIMITS ==="
echo "pid_max: $(cat /proc/sys/kernel/pid_max)"
echo "current process count: $(ls /proc | grep '^[0-9]' | wc -l)"
echo ""
echo "=== MEMORY FRAGMENTATION (buddyinfo) ==="
cat /proc/buddyinfo
echo ""
echo "=== SLAB USAGE ==="
grep -E 'SReclaimable|SUnreclaim|Slab' /proc/meminfo
echo ""
echo "=== HUGEPAGES ==="
grep -i huge /proc/meminfo | grep -v '^$'
echo ""
echo "=== MAX MAP COUNT ==="
echo "vm.max_map_count: $(cat /proc/sys/vm/max_map_count)"
echo ""
echo "=== TOP 10 MEMORY CONSUMERS ==="
ps aux --sort=-%mem | head -11
echo ""
echo "=== TOP 10 PROCESS COUNT BY USER ==="
ps aux | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
echo ""
echo "=== OOM KILLER HISTORY ==="
dmesg -T 2>/dev/null | grep -i 'out of memory\|killed process' | tail -20
echo ""
echo "=== RECENT ALLOCATION FAILURES ==="
dmesg -T 2>/dev/null | grep -i 'allocation failure\|alloc_pages' | tail -10
echo ""
echo "=== CGROUP CONSTRAINTS (if present) ==="
if [ -d /sys/fs/cgroup/pids ]; then
echo "cgroup v1 pids hierarchy found"
find /sys/fs/cgroup/pids -name 'pids.max' 2>/dev/null | while read f; do
max=$(cat "$f" 2>/dev/null)
cur=$(cat "${f%max}current" 2>/dev/null)
if [ "$max" != "max" ] && [ "$cur" != "" ]; then
ratio=$(( cur * 100 / max ))
if [ "$ratio" -gt 80 ]; then
echo "WARNING: $f: current=$cur max=$max usage=$ratio%"
fi
fi
done
fi
echo "=== DIAGNOSIS COMPLETE ==="
echo "Investigate the sections above for values near or at their limits."
Conclusion
The Cannot allocate memory error on Linux is a deceptive failure — its message suggests a simple lack of RAM, but the true root cause often lies in process limits, virtual memory overcommit policy, memory fragmentation, or kernel-level constraints. Effective root cause analysis requires systematically checking each layer: process counts and cgroup limits, virtual memory commitment ratios, buddy allocator fragmentation, HugePages reservations, vm.max_map_count, and slab cache consumption. By following the diagnostic methodology and applying the targeted fixes outlined in this tutorial, you can resolve the immediate failure and build preventive measures that keep your production systems resilient. The diagnostic script provided gives you a single-command snapshot to accelerate triage during incidents. Remember: in production, the goal is not just to fix the error when it occurs, but to instrument your systems so comprehensively that you detect the warning signs long before fork() ever fails.