zram vs Swap Partition on a VPS: Latency, Memory Savings and When Each One Hurts

On a VPS you cannot add physical RAM, so when memory pressure arrives you have two broad escapes: spill to disk-backed swap, or compress cold pages in RAM with zram. They behave nothing alike. Disk swap trades latency for capacity; zram trades CPU time for capacity without ever touching the disk. Choosing wrong produces either thrashing databases or burned CPU cycles. This article measures both and gives a decision rule.

How each mechanism actually works

A swap partition or file pages anonymous memory out to block storage. Every subsequent access is a page fault that must read from disk — on a shared NVMe VPS this is tens to hundreds of microseconds latency, and on a throttled volume it can be milliseconds. Sequential throughput may look fine while random fault latency destroys tail response times.

zram creates a compressed block device backed entirely by RAM. Pages written to it are compressed with LZ4 or zstd and stay in memory. A page fault triggers decompression, which costs CPU cycles but no disk I/O. Typical compression ratios of 2:1 to 4:1 mean 1 GB of zram can hold 2-4 GB of logical data.

Setting up zram on a small instance

# Debian/Ubuntu
apt install -y zram-tools

# size to roughly 50-100% of RAM, LZ4 for speed
cat >/etc/default/zramswap <<'EOF'
ALGO=lz4
PERCENT=75
PRIORITY=100
EOF

systemctl restart zramswap
swapon --show
zramctl

The PRIORITY matters: give zram a higher priority than any disk swap so the kernel prefers the compressed device, and keep disk swap as a last-resort safety net rather than the first line of defence.

Measuring the difference

Create controlled memory pressure and watch both the fault rate and the CPU cost. Using stress-ng with a memory worker bounded above available RAM forces the kernel to reclaim:

# watch fault behaviour and CPU sys time
vmstat 1 30 &
stress-ng --vm 1 --vm-bytes 90% --vm-hang 0 --timeout 60s

# per-process swap usage
for f in /proc/*/status; do \
  awk '/^Name|^VmSwap/{printf "%s ", $2}' $f; echo; \
  done | sort -k3 -n | tail -10
MetricDisk swapzram (LZ4)
Fault latency100 us – 5 ms5-50 us
CPU costminimalnotable (sys time up)
Effective capacityfull disk size2-4x RAM allocation
RiskI/O thrash, TTFB spikesCPU saturation, OOM at high ratio

When zram is the wrong answer

  • CPU-bound workloads. If your single vCPU already sits near 100%, adding compression work makes everything slower. Check with mpstat -P ALL 1 first.
  • Working sets that genuinely exceed 4x RAM. Compression cannot manufacture capacity; past a point you OOM just as hard, only later and with more CPU burned.
  • Databases with large page caches. A MySQL or PostgreSQL instance whose hot set is disk-resident gains little from compressing anonymous memory and may delay the honest signal that it needs more RAM.

When disk swap is the wrong answer

On a burstable or network-attached volume, sustained swap I/O competes with your application’s own reads. If vmstat shows swap-in (si) and swap-out (so) counters moving continuously, the instance is thrashing and no tuning will fix a genuinely undersized plan — see the instance-sizing guidance rather than fighting the symptom.

Monitoring zram effectiveness over time

Once zram is active, track the ratio and how much RAM you are actually recuperating. A high ratio is good for capacity but signals that pages compress well only because they are highly redundant; a low ratio with heavy use means you are burning CPU for little gain.

# DISK column shows logical size vs physical RAM consumed
zramctl

# watch allocation ratio and compression live
watch -n2 'zramctl --output NAME,DISKSIZE,DATA,COMPR,TOTAL'

# how much is the kernel spending on compression?
grep -E 'zram|zswap' /proc/vmstat
ObservationMeaningAction
COMPR ~3-4x, low CPUworking as intendedkeep as is
COMPR ~1.1x, high CPUpoorly compressible datareduce size or disable
DATA near DISKSIZEdevice nearly fulladd disk swap fallback
sys time peggedcompression bottleneckswitch algo to lz4, cut PERCENT

zstd vs lz4 for the compressed device

The algorithm choice is a direct latency-versus-capacity trade. LZ4 decompresses at multiple gigabytes per second per core and is nearly invisible in sys time; zstd compresses noticeably better, so more logical data fits, at a real CPU cost.

  • Single vCPU, latency-sensitive (web front end, DNS): LZ4. Compression cost must stay under a few percent.
  • Multi-core with headroom and a memory-hungry app: zstd, to squeeze more effective capacity from the same RAM.
  • Rule of thumb: if mpstat reports idle below 20% at peak, choose LZ4 or disable zram entirely.

A practical combined configuration

The best setup on a 2 GB VPS is usually both: zram at 50-75% with high priority, plus a modest 1-2 GB swap file as a pressure release valve, and a swappiness that encourages early use of the compressed device.

# prefer zram, keep disk swap as fallback
cat >/etc/sysctl.d/99-mem.conf <<'EOF'
vm.swappiness=100
vm.vfs_cache_pressure=50
vm.watermark_scale_factor=125
EOF
sysctl --system

# verify priorities: zram should be higher than /swapfile
swapon --show=NAME,TYPE,SIZE,PRIO

A high swappiness sounds counterintuitive, but when the swap device is fast compressed RAM you want cold anonymous pages moved out early to keep the page cache warm. When the only swap is disk, the conventional low value is correct. This is the single most misunderstood pairing in VPS tuning.

Decision rule

  • Idle CPU headroom above 30% and memory pressure is intermittent → zram.
  • CPU already saturated or working set far exceeds RAM → more RAM, not zram.
  • Volume is network-attached or throttled → avoid disk swap except as a crash guard.
  • Both available → zram high priority + small disk swap fallback, swappiness 100.

Measure before and after with the counters above; the difference in tail latency during pressure is usually dramatic and settles the argument quickly. Related memory-accounting techniques are covered in the tutorials section.

Leave a Reply