Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Linux Admins By James Joyner IV · · 9 min read Last reviewed Jul 2026

Linux Error Guide: 'earlyoom: mem avail 2%, swap nearly full' — Diagnose and Fix Memory Pressure

Quick answer

Diagnose Linux memory pressure before the OOM killer fires using free -h, vmstat, /proc/pressure/memory PSI, slabtop, smem, and cgroup v2 memory metrics.

  • #linux
  • #troubleshooting
  • #errors
  • #memory
Free toolkit

Stuck on this Linux Admins error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

Memory pressure describes the state where a Linux system is critically short on free RAM but has not yet crossed the threshold that triggers the OOM killer. The kernel begins aggressively reclaiming pages, reading and writing swap, and degrading throughput under that I/O load — all before any process is forcibly terminated.

Two early-warning signals surface in the logs before conditions become fatal. The earlyoom daemon, which proactively kills processes before the kernel OOM killer does, emits:

earlyoom[721]: mem avail:  180 of 7960 MiB ( 2.27%), swap free:    5 of 2047 MiB

Simultaneously, free -h shows a near-zero available column and an exhausted swap partition:

               total        used        free      shared  buff/cache   available
Mem:            7.8G        7.1G        120M        410M        580M        180M
Swap:           2.0G        2.0G          0B

Neither signal is a hard error that crashes a process — the system is still running — but both indicate the workload will soon degrade severely or that the OOM killer will fire unless pressure is relieved.

Symptoms

  • Interactive commands are sluggish; SSH sessions stall on output.
  • vmstat 1 shows non-zero si (swap-in) and so (swap-out) columns on every sample.
  • earlyoom or systemd-oomd writes warnings to the systemd journal at increasing frequency.
  • free -h shows the available column below 5% of total RAM.
  • Application response times increase; timeout errors appear in logs.
  • dmesg contains kswapd high-CPU entries or page-allocation failure traces.
  • Disk I/O spikes on the device that hosts the swap partition or swap file.

Common Root Causes

  • Memory leak — a process allocates memory over hours or days without releasing it; RSS grows without bound.
  • Undersized host — the combined working set of all running services exceeds installed RAM, leaving no headroom.
  • No swap or exhausted swap — without a swap overflow, memory pressure converts directly into OOM kills.
  • Cache thrashing — workloads that stream large datasets faster than the page cache can be reused force constant page reclaim.
  • Kernel slab growth — dentry and inode caches for filesystem-heavy workloads can consume gigabytes that are not visible as process RSS.
  • Many moderate leaks — dozens of small services each leaking a few hundred megabytes collectively exhaust available memory.

Diagnostic Workflow

Start with the high-level memory summary:

free -h

The critical number is the available column, not free. The free column counts only pages with no current mapping; available is the kernel’s own estimate of how much memory a new process could receive without pushing anything to swap. A low available value signals real pressure even when buff/cache appears large.

Pull key fields directly from the kernel memory accounting file:

grep -E 'MemTotal|MemAvailable|SwapTotal|SwapFree|Cached|Buffers' /proc/meminfo

Watch live swap activity. The si and so columns in vmstat count pages per second moving between RAM and swap:

vmstat 1 10

Sustained non-zero so (pages being swapped out) confirms ongoing pressure. If both si and so are non-zero simultaneously, the system is actively paging in both directions — a sign of severe thrashing.

Read Pressure Stall Information (PSI), the kernel’s built-in metric for how long processes actually stall waiting for memory:

cat /proc/pressure/memory
some avg10=45.23 avg60=38.10 avg300=12.45 total=89234567
full avg10=12.10 avg60=9.80 avg300=3.20 total=23451234

The some line means at least one process stalled; full means all runnable tasks stalled simultaneously. An avg10 (10-second average) above 10–20% indicates meaningful degradation; values above 40% mean the system is barely functional.

Identify which processes consume the most RAM:

ps aux --sort=-%mem | head -20

For more accurate accounting that subtracts shared library pages and shows swap usage per process:

smem -s swap -r | head -20

smem uses PSS (Proportional Set Size), which divides shared mappings proportionally among processes and adds their swap usage, giving a truer picture of per-process cost than RSS.

Check kernel slab allocations for filesystem-related cache growth:

sudo slabtop -o

Large values for dentry, inode_cache, or ext4_inode_cache indicate slab pressure distinct from process RSS.

For containerized services or systemd units under cgroup v2 resource control, inspect per-cgroup memory:

# Replace system.slice with the target cgroup path
cat /sys/fs/cgroup/system.slice/memory.current
cat /sys/fs/cgroup/system.slice/memory.pressure

memory.current gives current usage in bytes; memory.pressure mirrors the PSI format scoped to that cgroup alone.

Example Root Cause Analysis

A Java application server has been running for three days. earlyoom begins logging warnings every 30 seconds and vmstat shows continuous swap-out activity. The task is to find and remedy the source before the OOM killer fires.

Check the current memory split:

free -h
               total        used        free      shared  buff/cache   available
Mem:            7.8G        7.6G         85M        380M        115M        155M
Swap:           2.0G        1.9G         80M

Only 155 MiB available and 1.9 GiB of swap consumed. Find the heaviest consumers:

ps aux --sort=-%mem | head -5
USER       PID %CPU %MEM    VSZ      RSS   TTY STAT START   TIME COMMAND
tomcat    1842  4.2 68.3 9823456  5447680 ?   Sl  Mon09 412:13 java -Xmx4g -jar app.jar

The JVM process holds 68% of RAM despite a -Xmx4g heap cap. Native memory, direct byte buffers, or a metaspace leak is growing outside the JVM heap.

Confirm with smem to see swap contribution:

sudo smem -s swap -r | grep tomcat
 1842 tomcat    java        5447680   4831200   1953280

Nearly 2 GiB of the process’s pages have been paged out. With swap near exhaustion, the next significant allocation will trigger an OOM kill.

Immediate relief — restart the service:

sudo systemctl restart tomcat
free -h   # confirm available memory recovers

Long-term — enable JVM native memory tracking to locate the leak source:

# Add to JVM startup flags, then query after the service is running
java -XX:NativeMemoryTracking=detail ...
jcmd <pid> VM.native_memory summary

Prevention Best Practices

  • Set cgroup memory limits for every service so no single process can consume all RAM. Use MemoryMax= in systemd unit files or memory.max in cgroup v2 directly.
  • Configure adequate swap — at minimum 1–2 × RAM for hosts under 8 GiB. A swap partition is a safety net, not a substitute for sufficient RAM, but its absence accelerates OOM kills.
  • Deploy earlyoom or enable systemd-oomd so a controlled process is sacrificed before the kernel’s less-informed OOM killer acts.
  • Alert on MemAvailable — Prometheus node_exporter exposes node_memory_MemAvailable_bytes. Alert when it falls below 10% of total RAM.
  • Alert on PSInode_exporter also exposes /proc/pressure/memory. Alert when some avg60 exceeds 5% for sustained periods.
  • Tune vm.swappiness — the default of 60 allows the kernel to swap cached pages fairly aggressively. Lowering it to 10 tells the kernel to prefer keeping anonymous pages in RAM:
sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-memory.conf
  • Profile leaks rather than perpetually adding RAM. Use Valgrind or Heaptrack for C/C++ services, async-profiler for JVM, or memory_profiler for Python.

Quick Command Reference

# Memory and swap overview
free -h

# Key kernel memory fields
grep -E 'MemAvailable|SwapFree|SwapTotal' /proc/meminfo

# Live swap activity (si = swap-in pages/s, so = swap-out pages/s)
vmstat 1 5

# Pressure Stall Information
cat /proc/pressure/memory

# Top memory consumers by RSS
ps aux --sort=-%mem | head -20

# PSS and swap per process (more accurate than RSS)
smem -s swap -r | head -20

# Kernel slab cache sizes
sudo slabtop -o

# Per-cgroup memory usage and pressure (cgroup v2)
cat /sys/fs/cgroup/<unit>.service/memory.current
cat /sys/fs/cgroup/<unit>.service/memory.pressure

# Reduce swappiness (persist across reboots)
sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-memory.conf
sudo sysctl -p /etc/sysctl.d/99-memory.conf

Conclusion

Memory pressure is a pre-OOM warning state where the system fights to stay functional through aggressive page reclaim and swap I/O. Catching it early — through free -h’s available column, vmstat’s swap counters, PSI values in /proc/pressure/memory, and per-process tools like smem and ps — gives you time to identify and address the root cause before the OOM killer forces the issue. The most common culprits are memory leaks in long-running processes and undersized hosts relative to their workload. Once you know which process is growing beyond its expected footprint, you can restart it for immediate relief and then instrument it properly to eliminate the leak at its source.

Free download · 368-page PDF

Fixed it? Get 500 Linux Admins & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.