Skip to main content

Mastering Linux Memory: Swap, /proc/meminfo & OOM Guide

RAFSuNX
6 mins to read

Introduction

Memory management is at the heart of every Linux system’s performance and reliability. Whether you’re managing embedded devices, high-availability enterprise systems, containerized workloads, or high-performance computing clusters, a deep understanding of how Linux handles memory is critical. Unfortunately, Linux memory can appear cryptic at first glance: the fields in /proc/meminfo deviate from intuitive understanding, swap behavior mystifies many professionals, and out-of-memory (OOM) situations wreak havoc on production systems if left unchecked.

This post provides a comprehensive and tactical guide to mastering Linux memory management. We’ll dissect /proc/meminfo in detail, explore the mechanics of swap and swappiness, dive into how Linux selects processes for killing under memory pressure, and present specific approaches to optimize memory usage for performance-sensitive and mission-critical deployments.

Dissecting /proc/meminfo: What It Really Tells You

The /proc/meminfo virtual file provides a goldmine of real-time memory statistics. While common tools like free, vmstat, and top use this data, understanding the raw values gives you more insight into system behavior and anomalies.

Here’s a sample snippet from /proc/meminfo:

MemTotal:       16390348 kB
MemFree:         1284720 kB
MemAvailable:    8234560 kB
Buffers:          192640 kB
Cached:          3152948 kB
SwapCached:            0 kB
Active:          6823944 kB
Inactive:        3102952 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Dirty:               112 kB
Writeback:             0 kB

Key definitions:

  • MemTotal: Total usable RAM recognized by the kernel.
  • MemFree: Physical RAM not currently used.
  • MemAvailable: Estimated memory available for starting new applications without swapping.
  • Buffers/Cached: Memory used by kernel buffers and file caches - often reclaimable.
  • SwapTotal/SwapFree: Total size and free space of swap memory.

Important: Don’t mistake MemFree as the actual available memory - MemAvailable is the better gauge.

Interpreting Memory Pressure

To accurately determine if your system is under memory pressure:

  • Monitor MemAvailable - not just MemFree
  • If MemAvailable is low and SwapFree starts dipping, the system is starting to page out
  • If Cached and Inactive remain high under stress, memory reclaim is being deferred

Tune with:

sysctl -w vm.vfs_cache_pressure=75

This adjusts how aggressively the system reclaims cache memory to free RAM.

Swap Configuration: Beyond Defaults

Swap acts as an overflow area for RAM - disk-based, and therefore slower. But using swap smartly enhances stability under pressure.

Optimal Swap Size

General guidance:

  • <8GB RAM: Swap = 1.5–2x RAM
  • 8–16GB RAM: ~1x RAM
  • >16GB RAM: 4–8GB typically sufficient (or use ZRAM)

Use free -h to check if swap is active.

Tuning Swappiness: Prioritize RAM or Swap?

vm.swappiness defines how eagerly Linux pages memory to swap:

cat /proc/sys/vm/swappiness   # check current value
sysctl -w vm.swappiness=10    # set new value
echo "vm.swappiness=10" >> /etc/sysctl.conf
  • 0: Avoid swap unless absolutely necessary
  • 10: Good for low-latency workloads (databases, web servers)
  • 60 (default): Balanced
  • 100: Swap aggressively - use sparingly

Swap Types: Best Options for Your Use Case

Type Use Case Pros Cons
Swap File Flexible systems, VMs Easy to resize Slightly slower than partition
Swap Partition Static servers, performance-critical Fast access Hard to resize
ZRAM Embedded & low-RAM servers In-RAM compression = fast swap Uses RAM capacity

Setting Up Swap

# Create and enable a 4G swap file
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Persist in fstab
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Verify with:

swapon --show
free -m

Understanding & Troubleshooting the OOM Killer

When Linux runs critically low on memory, it invokes the Out-of-Memory (OOM) Killer to free up RAM by terminating processes. Understanding and configuring this behavior can prevent catastrophic service downtime.

How the OOM Killer Works

Each process is assigned an oom_score, calculating its likelihood of being killed under memory pressure. Influencing factors:

  • Memory usage
  • Whether the process is a child or forked
  • oom_score_adj (-1000 to +1000) modifies protection level

Inspect scores with:

cat /proc/<pid>/oom_score
cat /proc/<pid>/oom_score_adj

Increase survival priority for essential processes:

echo -1000 > /proc/<pid>/oom_score_adj

Linux logs OOM events to dmesg:

dmesg | grep -i 'oom'

Real-World Scenario: Java Process Killed

If your application like Tomcat or Kafka suddenly dies:

  • Check memory limits
  • Look for Killed process ... java in logs
  • Tune heap size using -Xmx and reduce resident usage

Preventing OOM Conditions Proactively

Apply Cgroups via systemd or Kubernetes

Limit memory usage per service:

# systemd
systemctl set-property myapp.service MemoryMax=512M

Kubernetes example:

resources:
  limits:
    memory: "1Gi"
  requests:
    memory: "512Mi"

User-Level Constraints

Use /etc/security/limits.conf to apply per-user memory caps:

# Limit address space to 2GB
username  hard  as  2097152

Adjust Memory Overcommit Control

sysctl -w vm.overcommit_memory=2
sysctl -w vm.overcommit_ratio=50
  • 0: Heuristic overcommit
  • 1: Always overcommit
  • 2: Cap to swap + RAM * overcommit_ratio

Use EarlyOOM or systemd-oomd

For desktops or Kubernetes nodes, these services act proactively on memory pressure.

Install EarlyOOM:

sudo apt install earlyoom

Monitor kill priority and act before the system freezes.

Optimizing Applications for Memory Usage

JVM Tuning

Avoid large default heap sizes:

-Xmx1024m -Xms512m

Use G1GC or Shenandoah collectors for memory-sensitive apps.

MySQL/PostgreSQL

Limit buffer sizes:

SET GLOBAL innodb_buffer_pool_size = 2G;

For PostgreSQL:

shared_buffers = 1GB
work_mem = 16MB

Caching Layers (Redis, Memcached)

Configure hard max memory and eviction policy:

maxmemory 512mb
maxmemory-policy allkeys-lru

Analyze Your App’s Memory Usage

Tools:

  • smem: Accurate RSS/PSS tracking
  • pmap -x <pid>: Per-process memory map
  • valgrind: Leak detection for custom apps
  • ps_mem.py: Human-readable memory report

Advanced Tips and Best Practices

Common Mistakes

  • Interpreting free without understanding cache/buffers
  • Disabling swap entirely in high-load environments
  • Forgetting to set oom_score_adj for core services
  • Overcommitting memory without restraint (type 1 setting)
  • Ignoring file-backed page cache buildup

Troubleshooting: Common Issues & Solutions

Symptom Cause Fix
OOM kills during builds High parallelism/low RAM Limit threads, increase swap
Swap fills despite RAM available High swappiness Reduce vm.swappiness
Important daemon terminated No oom protection Set oom_score_adj low
System freezes Overcommit + exhausted swap Set overcommit_memory=2, tune swap
Apps killed after deployment High RSS from warm caches Pre-tune limits, stagger startup

Best Practices Checklist

Task Recommendation
Swap Usage Use swap; avoid disabling without testing
Application Limits Apply memory caps via cgroups or limits.conf
OOM Protection Adjust oom_score_adj for key services
Monitor Regularly Use vmstat, smem, Prometheus, logs
Configure Alerts Set thresholds on MemAvailable and swap use
Test for OOM Scenarios Use stress-ng or similar to force trials
Profile Applications With valgrind, smem, perf, top

Resources & Next Steps

Key Docs:

Tools to Explore:

  • vmstat, smem, ps_mem, valgrind, heaptrack, perf
  • Visual dashboards: Netdata, Prometheus + Grafana

Next Actions:

  1. Audit current memory patterns on production nodes
  2. Enable and monitor swap intelligently
  3. Set up oom_score_adj and cgroup limits for key apps
  4. Use fault injection to simulate OOM conditions
  5. Regularly report memory and swap trends to improve forecasts

Conclusion

Mastering Linux memory is a vital step toward creating robust, performant infrastructure. From reading /proc/meminfo accurately to configuring swap for resilience and preventing OOM disasters, these fundamentals enable you to control system behavior during peak stress.

Key takeaways:

  • Understand and use /proc/meminfo metrics, focusing on MemAvailable
  • Configure swap wisely - never disable without real justification
  • Use oom_score_adj and cgroup memory limits to protect key processes
  • Optimize app behavior: define memory bounds in app configs
  • Test stress conditions before they happen in production

Control your memory landscape, reduce surprises, and build systems that thrive under pressure.

Happy coding!