Swap Reservation vs Actual Memory Pressure on Low-RAM VPS

A 512 MB VPS that reports 512 MB of memory is reporting a reservation, not a measurement. Of that, 60 to 120 MB is gone before you log in — kernel, page tables, slab caches — and the provider may also bill a swap reservation you never see. The gap between what is allocated and what is usable is where most small instances fail.

The visible symptom is the OOM killer arriving at 78% reported usage while free -m claims you have room. That is not a bug: page cache counts as used, but it is reclaimable, and the kernel will drop it rather than add swap. What cannot be dropped is anonymous memory, and that is what the OOM killer targets.

Read the four numbers that matter

free -m gives you total, used, free, shared, buff/cache and available. Most people watch free and panic, or watch used and relax. Watch available. It is the kernel’s own estimate of memory a new allocation could obtain without swapping, and on a healthy box it should stay above 15% of total under normal load.

free -m
grep -E 'CommitLimit|Committed_AS' /proc/meminfo
cat /sys/fs/cgroup/memory.max 2>/dev/null || cat /sys/fs/cgroup/memory/memory.limit_in_bytes

The cgroup limit is the real ceiling inside a container-based VPS, and it is frequently lower than MemTotal shown by the guest. If memory.max reads 402653184 while free says 512 MB, your true budget is 384 MB and everything you have been calculating is off by a quarter.

Swap reservation is not swap available

Some providers sell “512 MB RAM + 512 MB swap” as 1 GB. The swap is a file or partition on shared storage, and its throughput under contention can fall to a few hundred IOPS — so a workload that relies on it does not slow down gracefully, it stops. Check swapon --show and, more importantly, the host’s disk latency under swap pressure.

Measure it: allocate 200 MB beyond the RAM limit in a toy process and watch vmstat 1 for si/so. If pages swap out and in at more than a few thousand per second, the swap device is local NVMe and usable. If si stays near zero while the process hangs, the swap is on a throttled network volume and effectively decorative.

Even good swap only buys you time, not throughput. Once a working set no longer fits in RAM, every access to a swapped page costs a disk or network round trip, and latency rises by two or three orders of magnitude. Treat swap as a cushion that prevents the OOM killer from firing during a spike, never as capacity you can plan against.

Budget hosts differ sharply here. Those selling genuinely cheap RAM on entry-level low-memory instances often pair it with a small swap file precisely because they expect memory to run tight, so the quality of that swap matters more than the size printed on the plan.

Thresholds to size against

PlanAdvertisedTypical usableSafe steady load
Nano512 MB430–460 MB320 MB
Small1 GB880–950 MB700 MB
Medium2 GB1.8–1.9 GB1.5 GB
Large4 GB3.7–3.9 GB3.2 GB

Aim to keep peak anonymous usage below 75% of usable memory. The remaining quarter absorbs spikes, kernel overhead and whatever the package manager installs at 3 a.m. Going above 85% steady-state leaves no headroom for a single large request or a log rotation burst.

Make pressure visible before it kills something

Install pressure stall information as your primary alert. /proc/pressure/memory exposes some avg10 and full avg10; on a 1 GB instance, alert at some avg10 over 10 and at full avg10 over 2. These react to actual stalls rather than to a percentage that includes reclaimable cache, which makes them far less noisy than a used-memory threshold.

Pair it with a per-process view. ps -eo rss,comm --sort=-rss | head shows what is actually holding memory, and ss -m reveals per-socket buffers that can quietly hold tens of megabytes on a busy web server. On 512 MB, one runaway PHP worker at 80 MB is 16% of the box, and two of them will take it down.

Log the trend, not only the moment. A one-line cron job appending free -m, /proc/pressure/memory and the top three RSS consumers to a file every five minutes gives you a week of history for a few hundred kilobytes. When the box dies at 04:00 you will have the ten minutes before it, which is the only data that explains anything.

Watch for slow growth as well as spikes. A process gaining 2 MB an hour is a leak that will exhaust a 512 MB plan in roughly ten days, and it will look like a random nightly crash until you plot it. Restart-on-threshold is a valid stopgap while you find the cause.

Configuration changes that buy real headroom

Drop vm.swappiness to 10 so the kernel prefers reclaiming cache over swapping anonymous pages, and lower vm.vfs_cache_pressure to 50 to keep inode and dentry caches from being evicted too eagerly. Cap PHP-FPM pm.max_children from measured per-process RSS rather than guessing: usable memory divided by average worker size minus 20%.

  • Set a hard cgroup limit per service so one daemon cannot starve the box
  • Disable unused systemd units — bluetooth, modemmanager, snapd on some images
  • Use zram at 25–50% of RAM instead of disk swap on 512 MB plans
  • Rotate logs with compress and a 7-day retention; logs are a classic silent consumer

When to stop tuning and buy more RAM

If full avg10 stays above 5 for more than 10 minutes a day, tuning is over. That level of stall means requests are queuing behind memory reclaim, and the cost of the next tier — typically $2 to $4 per month on low-RAM VPS plans — is almost always less than the engineering time spent chasing it. Move up a tier, keep the tuning, and revisit only if pressure returns.

Affordable-Vps-Server-Author
Affordable-Vps-Server-Author
Articles: 392

Leave a Reply