Swap vs RAM: Diagnosing a VPS Quietly Running Out of Memory

Swap usage alone tells you nothing. This guide separates harmless cold pages from active thrashing, shows which process is being pushed out, and explains when to tune the working set versus buy more RAM.

A 2 GB VPS with a 2 GB swap file will appear healthy for months. Uptime is fine, monitoring shows no crashes, and the site loads — yet every page takes 300–900 ms longer than it should. That pattern is a memory shortage being absorbed by swap rather than reported as an incident. The table below separates normal swap use from the kind that means you are under-provisioned.

Swap usedSwap I/O rateInterpretationAction
0–5%0HealthyNone
5–25%0Cold pages parked, never touchedWatch only
5–25%Sustained >100 KB/sWorking set exceeds RAMFind the consumer, then size up
>50%AnyActive thrashingUpgrade RAM this week
100%HighOOM kills imminentUpgrade now

The distinction that matters is used versus actively moving. Swap pages that were written once and never read again cost nothing. Swap pages being read back under load cost disk latency on every request — typically 0.1–1 ms on NVMe and far worse on network-attached storage.

Measure Swap Activity, Not Swap Usage

# 1. How much is used at all
free -m | awk 'NR==3{printf "swap used: %s MB of %s MB\n", $3, $2}'

# 2. Is it actually moving? (run under real load)
vmstat 5 12 | awk 'NR>2{print "si:",$7" so:",$8" KB/s"}'

# 3. Which processes were swapped out
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
  awk '/VmSwap/{if($2>1000) print $2" kB", "PID "'$pid'}' /proc/$pid/status 2>/dev/null
done | sort -rn | head -10

# 4. Per-device swap I/O
sar -W 1 5 2>/dev/null || cat /proc/vmstat | grep -E 'pswp(in|out)'

Step 3 is the one most people skip. It tells you which process is being pushed out. If PHP-FPM workers dominate the list, the pool is too large. If MySQL dominates, the buffer pool is competing with the OS. If a single app worker dominates and grows over days, you have a leak that no RAM tier will fix permanently.

Distinguish Swap Latency From Server Latency

Confirm swap is the actual culprit before buying anything:

  • Compare TTFB cold versus warm. If the first request after a quiet period is 2–5× slower than later ones, pages are being faulted back from swap. The measurement method is covered in our latency and TTFB analysis guide.
  • Check disk read latency during traffic. Swap-ins show up as elevated await on the swap device in iostat -x.
  • Look at application-level p99. Swap affects tail latency first. A p99 that drifts while p50 stays flat is the classic signature.

Three Temporary Fixes, Ranked

1. Reduce the working set (best). Cut PHP-FPM pm.max_children, lower innodb_buffer_pool_size, cap journald, prune Docker images. This buys real headroom without changing the bill.

# PHP-FPM: size the pool to measured concurrency, not to RAM/40
pm = dynamic
pm.max_children = 8      # ~8 x 50 MB = 400 MB
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4

# MySQL: leave room for the OS and web tier
[mysqld]
innodb_buffer_pool_size = 512M

2. Tune swappiness down (temporary). Setting vm.swappiness=10 makes the kernel prefer dropping page cache over swapping application memory. It reduces churn but does not create capacity — it only delays the symptom.

3. Move swap to faster storage or add zram (temporary). Compressed RAM swap (zram) can absorb 200–400 MB of cold pages using far less physical memory than plain swap, and it is much faster than disk. It is a genuine stopgap for a small VPS, though it still consumes the RAM it is trying to save.

Sizing Swap Correctly First

Before diagnosing, confirm the swap file itself is not the problem. A common misconfiguration is a swap file created with the wrong permissions or on a filesystem that does not support it well, which produces slow swap even at low utilization.

Installed RAMRecommended swapSwappinesszram worth it?
512 MB1 GB60Yes, 256 MB
1 GB1–2 GB30–60Yes, 512 MB
2 GB2 GB10–30Optional
4 GB+2–4 GB10No
# Verify the swap file is correct
swapon --show
ls -l /swapfile        # expect -rw------- root root, mode 600
filefrag -v /swapfile | head -3   # check for fragmentation

# Fixed-size swapfile, no fragmentation
sudo swapoff /swapfile
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

The highest swappiness values belong on the smallest servers, because at 512 MB the alternative to swapping is an OOM kill. On a 4 GB server, swap is a crash cushion and nothing more, so swappiness of 10 keeps the kernel from parking live pages there. If measurement shows you are genuinely short on memory after tuning the working set, compare RAM tiers by price per usable gigabyte on the provider comparison table rather than jumping a full plan tier on gut feeling.

Affordable-Vps-Server-Author
Affordable-Vps-Server-Author
Articles: 342

Leave a Reply