Troubleshooting High Swap Usage Despite Free RAM
AI generated
$
/etc
Linux · Troubleshooting · Memory Management · MySQL
Troubleshooting High Swap Usage Despite Free RAM
Why the kernel swaps memory out even while free -h shows reserves

Several gigabytes of swap usage while free -h simultaneously reports plenty of free memory looks paradoxical, but is usually proactive, intentional kernel behavior rather than a fault. This guide shows how to use Pressure Stall Information, vmstat, and smaps to distinguish harmless from actually problematic swapping, what role swappiness really plays, and when MySQL buffer pool configuration is the actual cause.

17 min read PSI · vmstat · swappiness · smaps Linux · Troubleshooting · MySQL

1. Why swap usage with free RAM isn't a contradiction

Seeing several gigabytes of occupied swap in free -h while plenty of free memory is reported at the same time looks like a bug at first glance. In fact, this behavior is intentional in most cases: the Linux kernel proactively swaps out rarely used memory pages once they have not been touched for a while, in order to make the freed-up physical memory available for the page cache and actively used application data. This strategy follows the basic assumption that unused RAM is wasted RAM, and prioritizes active data over rarely used but still allocated memory.

The actual problem only arises when exactly these swapped-out pages are needed again shortly afterward and the kernel has to fetch them back from the significantly slower swap partition under time pressure. This situation, known as thrashing, shows up as noticeable latency and high I/O wait times, even though free -h still reports plenty of free memory. The central challenge in diagnosis therefore lies not in establishing that swap is being used, but in distinguishing between harmless, proactive swapping out and actually harmful, repeated thrashing.

2. Reading free -h correctly: available is not the same as free

A common misinterpretation of free -h is confusing the free and available columns. The free column shows completely unused memory reserved for neither applications nor the page cache, while available additionally includes memory currently sitting in the page cache but that can be released immediately and without performance loss if needed. A low free value alongside a high available value is entirely normal and merely shows that the kernel is using memory efficiently for caching, not that a shortage is imminent.

What matters for assessing swap usage is watching the used column of the swap row over time instead of evaluating a single value. A swap value that has been stable for days and does not change points to a one-time swap-out event further in the past and is usually unproblematic. A swap value that grows continuously and simultaneously coincides with rising CPU time in the %wa field (I/O wait) of top, on the other hand, is a clear warning sign of active, burdensome swapping that is actually impairing application performance.


# free vs. available — the distinction that matters
free -h
#               total        used        free      shared  buff/cache   available
# Mem:           31Gi        18Gi       1.2Gi       412Mi        12Gi        13Gi
# Swap:         8.0Gi       2.1Gi       5.9Gi

# A stable swap value that hasn't changed in days is usually harmless
# Log it over time to distinguish a one-time event from ongoing pressure
watch -n 300 'free -h | grep Swap'

3. vmstat and si/so: measuring activity instead of a snapshot

While free -h only shows a momentary state, vmstat 1 provides actual swap activity in real time via the si (swap in, pages loaded back from the swap partition into RAM) and so (swap out, pages newly swapped out) columns. Consistently high values in both columns simultaneously are the decisive signal for thrashing: the kernel swaps pages out and has to fetch them back shortly afterward, which points to a real memory shortage where the available RAM simply is not enough for the active workload.

Occasional short spikes in so without corresponding si activity, on the other hand, are unproblematic and correspond exactly to the proactive swapping out of rarely used pages described in the previous section. The rule of thumb: a one-time spike in so followed by silence is normal, a recurring pattern of alternating si and so over several minutes is a warning sign that justifies a deeper investigation of memory requirements.


# Live view of swap in/out activity, refreshed every second
vmstat 1 10

# procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
#  r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
#  2  1  2150400 125600 45200 12800000  0    0   120   340 1200 2400 12  4 82  2  0
#  3  4  2151200 118400 45200 12790000 45  180   890  1200 1800 3100 18  9 55 18  0
#                                      ^^^  ^^^ — sustained si+so = real thrashing

# Aggregate view without the noise: only si/so columns over time
vmstat 1 60 | awk '{print $7, $8}'

4. Pressure Stall Information: measuring real memory pressure

Pressure Stall Information (PSI), available since kernel 4.20 under /proc/pressure/memory, is the most precise tool available for directly quantifying memory pressure instead of inferring it from proxies such as swap usage. PSI measures what percentage of time at least one process (some) or all processes simultaneously (full) were blocked due to missing memory, aggregated over 10 seconds, 60 seconds, and 5 minutes. A full avg10 value near zero means that despite swap usage, practically no process was noticeably slowed down by memory shortage, which classifies the previously observed swap activity as unproblematic.

If the full avg10 value rises above a low single-digit percentage range, applications spend measurable time blocked waiting for swapped-out pages currently being fetched back. In practice, this single value replaces the tedious manual correlation between vmstat activity, application latency, and CPU wait time, and should be the first thing to check whenever a swap problem is suspected, even before free -h or vmstat.


# The single most reliable indicator of actual memory pressure
cat /proc/pressure/memory

# some avg10=2.34 avg60=1.87 avg300=0.95 total=48291823
# full avg10=0.12 avg60=0.08 avg300=0.03 total=1204958
#                  ^^^^^^^^^ — near-zero "full" means no real stalling

# Alert threshold suggestion: full avg10 consistently above 5% warrants investigation
awk '/^full/ {print $2}' /proc/pressure/memory | grep -oP 'avg10=\K[0-9.]+'

5. Understanding and correctly placing swappiness

The vm.swappiness parameter (default usually 60) controls how aggressively the kernel prioritizes swapping out memory pages versus the page cache when memory becomes scarce, not whether swapping happens at all. A common misconception is assuming that vm.swappiness=0 disables swap entirely. In fact, since kernel 3.5, a value of 0 only means that swap is used exclusively as a last resort, shortly before the OOM killer would have to intervene, while values between 1 and 100 set the relative weighting between evicting page cache and swapping out application memory.

For database servers like MySQL, where the server's own buffer pool already represents the most effective caching layer, a lower value such as vm.swappiness=10 is often sensible, because it signals to the kernel to favor the page cache more strongly rather than swapping out actively used application memory in favor of file system caching. A swappiness value alone, however, does not solve any underlying capacity problem; it only shifts which type of memory is affected first when pressure actually rises.


# /etc/sysctl.d/99-swappiness.conf
# Lower value favors keeping application memory resident,
# at the cost of evicting page cache more aggressively under pressure.
# Recommended starting point for database servers (MySQL/MariaDB).
vm.swappiness = 10

sudo sysctl --system

# Verify the active value
cat /proc/sys/vm/swappiness

6. Using smaps to find out what was actually swapped out

Once PSI confirms real memory pressure, the next step is finding out which process is responsible for the swapped-out pages. /proc/[pid]/status provides the per-process swapped-out memory amount via VmSwap, while smem -st swap provides an overview of all processes sorted by swap usage. A process with a strikingly high VmSwap value relative to its VmRSS indicates that a substantial part of its memory has not been actively used for a while, which can be entirely normal for a database server or a PHP-FPM master process with rarely used but allocated buffers.

For an even more precise analysis, /proc/[pid]/smaps shows the swap portion per individual memory mapping, which helps distinguish between swapped-out heap memory, swapped-out shared memory segments, and swapped-out library mappings. This breakdown is particularly valuable when there is a suspicion that a specific application component, for example a rarely used admin area of a Magento installation, allocates an unnecessary amount of memory that is then rightfully swapped out, rather than there being an actual configuration problem.


# Per-process swap usage, sorted highest first
smem -st swap

#   PID User     Command                         Swap      USS      PSS      RSS
#  1823 mysql    /usr/sbin/mysqld                512.0M   890.2M   920.4M  1024.8M
#  4821 www-data php-fpm: master process         128.4M    12.1M    18.9M    22.4M

# Breakdown of swapped memory within a single process's mappings
grep -B2 "^Swap:" /proc/1823/smaps | grep -A2 "^7f" | head -30

7. MySQL and the buffer pool: a common special case

For MySQL servers, swap usage is a particularly common and at the same time particularly critical topic, because the InnoDB buffer pool is deliberately configured to occupy a large portion of available RAM in order to minimize disk access. If innodb_buffer_pool_size is sized too generously, for example at 80 percent of total memory on a server that also runs PHP-FPM workers and other services, the buffer pool actively competes with these services for physical memory, and the kernel starts swapping out rarely used buffer pool pages.

The actual problem here: swapped-out buffer pool pages are useless to MySQL once they are actually needed for a query, because fetching them back from the swap partition is orders of magnitude slower than a direct disk access via InnoDB itself would have been. In this case, the solution is not adjusting swappiness but correctly sizing innodb_buffer_pool_size while accounting for all other services on the same server, typically at 60 to 70 percent of available RAM instead of a blanket 80 percent rule that ignores co-located services.

8. cgroup v2 memory pressure for container workloads

In containerized environments, cgroup v2 provides the same PSI metric as the system-wide /proc/pressure/memory via memory.pressure, but isolated to the respective cgroup, which is particularly valuable for Docker containers and systemd services with their own memory limit. A container that reaches its memory.max limit starts swapping (unless memory.swap.max is set to 0) or gets terminated by the cgroup OOM killer, independent of the host's overall memory state. The system-wide free -h output can look entirely unremarkable while a single container is already under considerable internal memory pressure.

For Magento setups with multiple containers on the same host, targeted monitoring of memory.pressure per cgroup is therefore more informative than the system-wide view, because it shows precisely which individual service is actually under pressure, rather than providing an aggregated value that can mask local bottlenecks.


# Per-cgroup memory pressure, isolated from the rest of the host
cat /sys/fs/cgroup/system.slice/docker-<container-id>.scope/memory.pressure

# Current memory limit and swap configuration for a specific cgroup
cat /sys/fs/cgroup/system.slice/docker-<container-id>.scope/memory.max
cat /sys/fs/cgroup/system.slice/docker-<container-id>.scope/memory.swap.max

9. Normal vs. problematic swapping compared

The overview below summarizes the key signals for distinguishing between harmless and actually problematic swapping.

Signal Normal Problematic
Swap used (free -h) Stable over days, no change Continuously growing
vmstat si/so One-time so spike, then quiet Sustained si/so alternation
PSI full avg10 Near 0 percent Clearly above 5 percent
Application latency Unchanged Noticeably elevated, correlates with so

Only when several of these signals fall into the problematic column simultaneously, especially an elevated PSI value combined with sustained si/so activity, is actual thrashing present that justifies a capacity increase or a memory configuration adjustment. A stable swap value viewed in isolation, without these accompanying signals, requires no action and is normal, efficient kernel behavior instead.

Mironsoft

Linux memory analysis and database tuning for Magento infrastructure

Swap alerts without actual memory pressure?

We analyze your memory usage with PSI and vmstat, distinguish harmless from actually problematic swapping, and size MySQL buffer pool and swappiness to match your real workload.

Memory Pressure Audit

PSI-based analysis of whether swap usage is actually slowing down applications

MySQL Tuning

Buffer pool sizing that accounts for all services running on the server

Capacity Planning

Reliably separating real bottlenecks from harmless, proactive swapping

10. Summary

High swap usage despite free RAM in free -h is, in most cases, not a bug but proactive kernel behavior that swaps out rarely used memory pages in favor of the page cache and actively used data. The decisive question is not whether swap is being used, but whether this swapping actually leads to noticeable thrashing. Pressure Stall Information under /proc/pressure/memory provides the most precise, directly interpretable metric for this, complemented by sustained si/so activity in vmstat as confirmation.

Swappiness only influences which type of memory is affected first, but does not solve a capacity problem itself. For database servers, correctly sizing innodb_buffer_pool_size while accounting for all co-located services is often more important than any swappiness adjustment. Anyone combining PSI, vmstat, and smaps reliably distinguishes between normal, efficient memory behavior and an actual bottleneck that justifies a capacity increase.

Troubleshooting High Swap Usage: The Essentials at a Glance

Baseline behavior

The kernel proactively swaps out rarely used pages to prioritize page cache and active data.

Key metric

PSI full avg10 from /proc/pressure/memory shows directly whether processes are actually being slowed down.

Swappiness role

Only controls priority between page cache and application memory, does not solve a capacity problem.

MySQL special case

Size innodb_buffer_pool_size correctly instead of treating swappiness as a quick fix.

11. FAQ: Troubleshooting High Swap Usage Despite Free RAM

1Why is swap used with free RAM?
Proactive swapping out of rarely used pages to prioritize page cache and active data. Intentional, not a bug.
2Difference between free and available?
free is completely unused, available also includes immediately releasable page cache.
3Recognizing real thrashing in vmstat?
Sustained high si and so simultaneously over several minutes, not a one-time spike.
4What is Pressure Stall Information?
Directly measures what percentage of time processes were blocked due to memory shortage.
5Does swappiness=0 disable swap fully?
No, since kernel 3.5 only a last resort before OOM kill. Full disabling needs swapoff -a.
6Which swappiness for MySQL?
Often vm.swappiness=10, since the buffer pool is already the most effective caching layer.
7Which process swapped out memory?
smem -st swap sorts all processes by swap usage.
8Why is swap critical for MySQL?
Swapped-out buffer pool pages are orders of magnitude slower to fetch back than InnoDB disk access.
9Monitoring memory pressure per container?
cgroup v2 memory.pressure provides isolated PSI per container, more informative than the host value.
10When to expand capacity instead of configuring?
With consistently high PSI full avg10 above 5 percent together with sustained si/so activity and noticeable latency.