There’s a particular moment every sysadmin has: a server is “slow,” nobody can say exactly why, and top just shows a wall of numbers refreshing every two seconds without telling a clear story. That’s usually when I reach for vmstat. It’s not flashy, it doesn’t have colors or a fancy TUI, but it gives me the one thing I actually need in that moment — a clean, columnar snapshot of what the kernel is doing across processes, memory, swap, I/O, and CPU, all in one line I can read at a glance.
This guide covers vmstat from “what is this tool” all the way to using it for serious performance diagnosis on production systems.
What Is vmstat?
vmstat stands for virtual memory statistics. It’s part of the procps (or procps-ng) package on most distributions, and like most of the tools in that family, it’s really just a formatted reader of data from /proc — mainly /proc/meminfo, /proc/stat, and /proc/vmstat.
Checking the version on my system:
vmstat --version
vmstat from procps-ng 4.0.4
Running it with no arguments gives a single summary snapshot:
vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
0 0 0 3830708 11696 132364 0 0 4844 1 304 5 10 38 51 1 0 0
That’s a lot packed into two lines. Let’s take it apart column by column, because understanding this table is the entire point of learning vmstat.
Understanding Every Column
procs (Process Statistics)
- r — number of processes currently runnable, i.e., waiting for CPU time (in the run queue, not necessarily blocked). If this number is consistently higher than your CPU core count, you have CPU contention.
- b — number of processes in uninterruptible sleep, usually waiting on I/O. A persistently high
bvalue is one of the strongest signals of a disk I/O bottleneck.
memory (in KB by default)
- swpd — amount of virtual memory currently swapped out to disk.
- free — amount of idle memory, completely unused.
- buff — memory used as buffers (raw disk blocks).
- cache — memory used as page cache (file contents cached from disk).
A common beginner mistake is panicking over a low free value. On a healthy Linux system, the kernel deliberately uses “unused” RAM for cache, because cache can be reclaimed instantly. What matters more is whether swpd is climbing.
swap
- si — amount of memory swapped in from disk, per second.
- so — amount of memory swapped out to disk, per second.
Any sustained non-zero values here are a red flag. Swapping means the kernel had to move memory pages to disk because physical RAM was under pressure, and disk is orders of magnitude slower than RAM. If si/so are consistently active, the system needs more RAM, or something is consuming more than it should.
io
- bi — blocks received from a block device (reads), in blocks/second.
- bo — blocks sent to a block device (writes), in blocks/second.
These give you a rough sense of disk activity without needing iostat.
system
- in — interrupts per second, including the clock.
- cs — context switches per second.
A sudden spike in cs can indicate a process (or many processes) thrashing between CPU and waiting states — common with lock contention or a runaway scheduler situation.
cpu (percentages)
- us — time spent running user-space (non-kernel) code.
- sy — time spent running kernel code (system calls, interrupts).
- id — idle time.
- wa — time spent waiting on I/O. This is often the single most diagnostic number on the whole line — high
wawith lowus/symeans the CPU is sitting there waiting for disk, not actually computing anything. - st — “stolen” time, relevant in virtualized environments — time the hypervisor gave to other VMs instead of yours.
- gu — guest time, time spent running a virtual CPU for a guest OS (shown on some kernel versions with virtualization support).
On my sandbox environment (a VM), the extra gu column shows up because of the virtualized CPU:
us sy id wa st gu
10 38 51 1 0 0
Full Syntax and Options
vmstat [options] [delay [count]]
The real power of vmstat is in the delay and count arguments:
vmstat 2 5
This prints a new line every 2 seconds, 5 times total. This is how you actually watch trends instead of a single frozen snapshot — I almost never run plain vmstat on a real investigation; I run it with a delay.
Key flags, pulled straight from vmstat --help on my system:
Options:
-a, --active active/inactive memory
-f, --forks number of forks since boot
-m, --slabs slabinfo
-n, --one-header do not redisplay header
-s, --stats event counter statistics
-d, --disk disk statistics
-D, --disk-sum summarize disk statistics
-p, --partition <dev> partition specific statistics
-S, --unit <char> define display unit
-w, --wide wide output
-t, --timestamp show timestamp
-y, --no-first skips first line of output
-a: Active/Inactive Memory
vmstat -a
Replaces the buff/cache columns with inact (inactive) and active memory — useful when you want to see how much cached memory the kernel considers reclaimable versus actively in use.
-s: Full Statistics Dump
This is one of my favorites for a full picture in one shot:
vmstat -s
4093928 K total memory
313728 K used memory
76908 K active memory
75032 K inactive memory
3830456 K free memory
11696 K buffer memory
132364 K swap cache
0 K total swap
0 K used swap
0 K free swap
189 non-nice user cpu ticks
0 nice user cpu ticks
698 system cpu ticks
962 idle cpu ticks
18 IO-wait cpu ticks
0 IRQ cpu ticks
4 softirq cpu ticks
0 stolen cpu ticks
0 non-nice guest cpu ticks
0 nice guest cpu ticks
This is essentially a cumulative counter view rather than a rate — useful for a “since boot” summary.
-d: Disk Statistics
vmstat -d
Shows per-disk reads, writes, I/O time, and merges — a lighter-weight alternative to iostat when you just need a quick check and don’t have sysstat installed.
-m: Slab Info
vmstat -m
Shows kernel slab allocator statistics — how much memory the kernel itself is using for internal object caches (inodes, dentries, network buffers, etc.). This one’s more of a kernel-internals diagnostic than a typical sysadmin daily-driver, but it matters when you suspect kernel memory (not user-space memory) is what’s growing unbounded.
-S: Unit Conversion
vmstat -S M
Displays memory figures in megabytes instead of kilobytes. Valid units: k (1000), K (1024, default), m (1,000,000), M (1,048,576).
-t: Timestamps
vmstat -t 2 5
Adds a timestamp column to each line — essential if you’re logging vmstat output to a file for later analysis, since otherwise you can’t correlate a spike with wall-clock time.
How vmstat Works Internally
vmstat doesn’t maintain its own state or talk to the kernel through special system calls. On Linux, it reads directly from:
/proc/meminfo— memory figures/proc/stat— CPU ticks, interrupts, context switches, forks/proc/vmstat— detailed virtual memory event counters/proc/diskstats— for the-ddisk statistics mode
For rate-based columns (si, so, bi, bo, in, cs), vmstat calculates the delta between two reads of the underlying counters, divided by the elapsed time — which is exactly why the very first line of vmstat‘s output (when run without a delay, or the first line of a delayed run) represents averages since boot, not a live rate. Every subsequent line in a delayed run is a genuine live rate over that interval. This trips people up constantly: if you only run vmstat once, you’re seeing a boot-to-now average, not “right now.” Always use a delay and look at the second line onward for real-time data.
Real-World Use Cases
Quick health check during an incident:
vmstat 1 10
Watch the r, wa, and si/so columns for ten seconds. If r is way above your core count and wa is climbing, you likely have I/O-bound contention, not CPU-bound.
Logging for later analysis:
vmstat -t 5 720 > /var/log/vmstat_$(date +%F).log &
This logs a timestamped sample every 5 seconds for an hour (720 samples), backgrounded — a common pattern I use before a load test or deployment window so I have hard data if something goes wrong.
Detecting memory pressure in a monitoring script:
#!/bin/bash
SWAP_IN=$(vmstat 1 2 | tail -1 | awk '{print $7}')
if [ "$SWAP_IN" -gt 0 ]; then
echo "ALERT: active swapping detected (si=$SWAP_IN)" | logger -t vmstat-check
fi
Diagnosing a “slow but idle-looking” server: if top shows low CPU usage but users report slowness, vmstat 1 5 with a consistently non-zero wa column usually points straight at disk I/O as the real bottleneck — a network storage mount timing out, a failing disk, or a backup job hammering I/O in the background.
vmstat vs Related Commands
| Tool | Best For | Weakness |
|---|---|---|
vmstat | Fast overall system snapshot: CPU, memory, swap, I/O in one line | No per-process breakdown |
top / htop | Per-process CPU/memory ranking, interactive | Busier display, harder to log cleanly |
iostat | Deep per-device disk I/O statistics | Requires sysstat package, not always installed by default |
free | Memory-only snapshot, easier to read for just RAM/swap | No CPU or I/O context |
sar | Historical, logged system performance data (needs sysstat) | Requires setup/cron beforehand; not useful retroactively without it |
My personal rule of thumb: vmstat first for the “what’s generally going on” question, then top/htop if it looks CPU or process related, then iostat if it looks disk related.
Performance Optimization Notes
- If
si/soare consistently non-zero, adding RAM or reducing memory-hungry processes is the real fix — swap is a symptom, not the disease. - If
wais consistently high, check disk health (smartctl), consider faster storage (SSD/NVMe), or investigate what’s generating so much I/O (iotopcan identify the specific process). - A consistently high
cs(context switches) relative to your workload can point to lock contention in an application, or too many threads competing for too few cores.
Security Implications
vmstat itself is a read-only reporting tool and doesn’t modify system state, so it carries essentially no direct security risk. The one thing worth noting: its output can reveal system load patterns and memory pressure to any local user (it doesn’t require root), which in shared/multi-tenant systems could theoretically be used for reconnaissance in a side-channel sense — though this is a minor and largely theoretical concern compared to more direct information leaks elsewhere on the system.
Compatibility Across Distributions
vmstat is part of procps / procps-ng, which ships by default on essentially every mainstream Linux distribution — Debian, Ubuntu, RHEL, CentOS, Fedora, Arch, openSUSE. Minor differences exist between very old procps versions and the newer procps-ng fork (which most distros migrated to years ago), mainly in extra columns like gu (guest time) and some flag names, but the core column layout has been stable for decades.
Reading a Real Diagnostic Session Start to Finish
It helps to walk through how these pieces fit together during an actual investigation rather than treating each column as an isolated fact. Say a report comes in that an application feels sluggish. The first move is vmstat 1 10, watching ten seconds of live samples rather than a single snapshot. If the r column sits comfortably below core count, CPU scheduling contention is probably not the story. If wa is elevated and the b column shows processes stuck in uninterruptible sleep, the next move is confirming disk involvement with iostat -x 1 (if available) or checking vmstat -d for per-device read/write counts. If instead si/so are both non-zero and climbing, the story shifts to memory pressure, and the next step becomes identifying which process is consuming the most RSS memory rather than chasing disk I/O at all. This kind of layered elimination — ruling categories out with vmstat before reaching for a heavier, more specific tool — is the actual skill worth building, more so than memorizing any single column in isolation.
Summary
vmstat earns its place as one of the first tools I reach for during any performance investigation because it condenses process, memory, swap, I/O, and CPU activity into one readable line, refreshed at whatever interval I choose. It’s not a replacement for deeper tools like iostat or per-process profilers, but as a fast, dependency-light “what’s actually going on right now” check, it’s hard to beat — and understanding its columns makes every other monitoring tool on Linux easier to read too.
References
man 8 vmstat- procps-ng project: https://gitlab.com/procps-ng/procps
- Linux kernel documentation:
Documentation/filesystems/proc.rst man 5 proc
