When your server's RAM fills up, Linux moves inactive memory pages to swap (disk). This is normal in small amounts, but excessive swapping (thrashing) makes your server extremely slow because disk I/O is thousands of times slower than RAM access. This guide covers identifying, diagnosing, and fixing swap thrashing.
Identify Thrashing
# Check swap usage
free -h
# If Swap "used" is high and "available" memory is low, you may be thrashing
# Check swap activity (si=swap-in, so=swap-out)
vmstat 1 10
# High si/so values (>1000) indicate active thrashing
# Check which processes use swap
# Method 1: Top sorted by swap
top -o SWAP
# Method 2: Check per-process swap usage
for pid in /proc/[0-9]*; do
name=$(cat $pid/comm 2>/dev/null)
swap=$(awk '/VmSwap/{print $2}' $pid/status 2>/dev/null)
if [ -n "$swap" ] && [ "$swap" -gt 0 ]; then
echo "${swap} kB - $name (PID $(basename $pid))"
fi
done | sort -rn | head -20
# Method 3: smem (more accurate)
sudo apt install smem
smem -s swap -r | head -20
Find the Memory Hog
# Top memory consumers
ps aux --sort=-%mem | head -20
# Check total memory usage by service
systemctl --type=service --state=running | while read unit _; do
pid=$(systemctl show -p MainPID "$unit" 2>/dev/null | cut -d= -f2)
if [ "$pid" -gt 0 ] 2>/dev/null; then
rss=$(ps -o rss= -p "$pid" 2>/dev/null)
echo "${rss:-0} kB - $unit"
fi
done | sort -rn | head -15
# Common memory hogs:
# - MySQL/PostgreSQL with large buffer pools
# - Java applications with large heap
# - Redis/Memcached without memory limits
# - PHP-FPM with too many workers
# - Node.js applications with memory leaks
Immediate Fixes
# 1. Kill the biggest memory consumer (if non-critical)
kill -15 PID
# 2. Reduce application memory usage
# MySQL: Lower innodb_buffer_pool_size
# PostgreSQL: Lower shared_buffers
# PHP-FPM: Reduce pm.max_children
# Node.js: Set --max-old-space-size
# 3. Clear swap (move pages back to RAM if RAM is available)
sudo swapoff -a && sudo swapon -a
# WARNING: This hangs if there's not enough free RAM
# 4. Safer swap clear (only if free RAM > used swap)
free_ram=$(free -m | awk '/Mem:/{print $7}')
used_swap=$(free -m | awk '/Swap:/{print $3}')
if [ "$free_ram" -gt "$used_swap" ]; then
echo "Safe to clear swap ($free_ram MB free > $used_swap MB swap)"
sudo swapoff -a && sudo swapon -a
else
echo "NOT safe! Free RAM ($free_ram MB) < Used swap ($used_swap MB)"
fi
Tune Swappiness
# Check current swappiness (default: 60)
cat /proc/sys/vm/swappiness
# Lower swappiness = less eager to swap
# 10 is good for servers (keep things in RAM longer)
echo 10 | sudo tee /proc/sys/vm/swappiness
# Make persistent
echo "vm.swappiness = 10" | sudo tee -a /etc/sysctl.d/99-swappiness.conf
sudo sysctl -p /etc/sysctl.d/99-swappiness.conf
# For database servers, consider swappiness=1
# (almost never swap, but still allow it in emergencies)
Right-Size Your Services
# MySQL/MariaDB — buffer pool should be ~70% of RAM for dedicated DB
# /etc/mysql/mysql.conf.d/mysqld.cnf
innodb_buffer_pool_size = 2G # Adjust based on available RAM
# PostgreSQL — shared_buffers should be ~25% of RAM
# /etc/postgresql/16/main/postgresql.conf
shared_buffers = 1GB
effective_cache_size = 3GB
# PHP-FPM — calculate max_children based on RAM
# max_children = (Available RAM - Other services) / per-process memory
# Typical PHP process: 30-60MB
# With 4GB RAM, 2GB for other services: (4096-2048)/50 = ~40 workers
pm = dynamic
pm.max_children = 40
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
# Redis — set a memory limit
maxmemory 512mb
maxmemory-policy allkeys-lru
Add More Swap (Temporary Relief)
# Create swap file
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# Make persistent
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# Verify
swapon --show
Best Practices
- Monitor swap usage continuously — alert when swap exceeds 50% used
- Set swappiness to 10 on servers to prefer RAM over swap
- Right-size your applications: Configure memory limits for all major services
- Upgrade RAM if you consistently need more memory than available
- Never disable swap entirely on production servers — it's a safety net for OOM
- Watch vmstat si/so columns — active swapping above 1000 KB/s indicates a problem