vmstat Command: Tutorial & Examples
Six subsystems on one line — the highest-level dashboard Linux ships with.
What It Is
vmstat is misnamed and that's the first thing to know about it. It says "virtual memory statistics" on the tin, but what it actually prints is a tiny, dense dashboard of six different kernel subsystems on a single line: process queues, memory state, swap traffic, block I/O, interrupts and context switches, and CPU breakdown. One row, six worlds. It's the command a veteran types first when a server feels wrong and they don't yet know which subsystem is sick — because vmstat tells you where to look next, in less than five seconds, and then you reach for the specialist.
That framing is the whole point of this page. top shows you processes. free shows you memory state. iostat shows you per-disk I/O detail. vmstat shows you subsystems — and tells you which one to zoom into with the specialist tools. If free sent you here looking for the real swap-thrashing alarm (the si / so columns), you're in the right place: jump to How I Read It and then the Columns section. We'll walk every column, teach you the order a veteran's eyes move, and along the way pick up how the Linux kernel actually divides its time between six very different jobs.
Note
vmstatis misnamed. It's not primarily about virtual memory — it's a six-subsystem dashboard (procs+memory+swap+io+system+cpu) on one row. Think of it as "top's summary lines without the process table, plusiostat's aggregate, plus the swap-rate alarmfreecan't show you" — fused into a single 80-column line that updates every N seconds.
Your First Look
The canonical invocation is two arguments: how often to sample, and how many samples to print. Two seconds, three samples, is the one to memorize:
vmstat 2 3
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
1 0 8066500 13335244 205556 9049872 27 42 1034 2500 2342 7 4 1 95 0 0 0
2 0 8066500 13326716 205556 9050016 0 0 46 108 3289 14239 9 2 90 0 0 0
1 0 8066500 13317140 205580 9050016 0 0 4 90 3853 17518 12 3 85 0 0 0
Three lines of numbers, sixteen columns, six groups separated by dashed headers. The groups are the whole map: procs (the run queue), memory (free / cached), swap (in / out rate), io (block in / out), system (interrupts and context switches per second), and cpu (the same us / sy / id / wa / st breakdown you know from top). Read across left-to-right and you're reading the whole machine.
Pro Tip
ignore the first row, every time. The first line
vmstatprints is the average since boot — basically useless for diagnosing a live problem on a server that's been up for weeks. Trust the second row onward; those are the rolling N-second samples that show you what's happening now. Or skip the first row entirely withvmstat -y 2 3(the-yflag was added precisely for this).
How I Read It
When a box feels sick and I'm hunting for "which subsystem is hurting?", here's the muscle memory — about five seconds, left to right across one of those rolling rows.
First, procs: r and b. r is the run queue — processes that want the CPU right now. If r is steadily above the core count from nproc, the box is CPU-bound and something is queuing. b is processes blocked on I/O — the same D-state count top and ps call uninterruptible sleep. A high b with low r means the CPU is fine but the disk (or NFS, or any kernel wait) is the bottleneck — exactly the high-load-with-idle-CPU story from the top page, but here you see the count, not just the load average. This is the load average broken open.
Second, swap: si and so. This is the alarm column. Not "is swap used" — that's swpd in the memory group, and a non-zero swpd is normal and fine (see free for why). The dangerous question is: is the kernel actively shuffling pages in and out of swap right now? Non-zero si (swap-in, KiB/s) or so (swap-out, KiB/s) sustained over multiple samples means the box is thrashing — performance falls off a cliff, because every page fault costs a disk round-trip. This single column is what free sends people here to find. If si/so are zero, swap is healthy regardless of how much is used. If they're non-zero on a steady-state row, you have a real memory problem.
Third, cpu: same letters as top. us user, sy kernel, id idle, wa I/O wait, st stolen by the hypervisor, gu running KVM guest code. High wa says the CPU is busy waiting for the disk — next stop, iostat. High st on a cloud VM means a noisy neighbour is eating your cycles. High sy often means a syscall storm (lots of small files, lots of network packets) — chase with strace or perf.
Fourth — and this one's a hidden gem — system: cs. Context switches per second. A normal idle server is 50-200; a healthy busy web server runs in the low thousands; tens of thousands of cs/s is pathological and one of the few signals that points straight at application design, not resource exhaustion. Over-threaded apps, lock contention, badly-tuned thread pools — they all show up here when nothing else looks wrong. The CPU might read id 60, memory fine, disk quiet, and yet the box feels sluggish because half its time is going to kernel bookkeeping. cs is how you catch it.
Fifth, memory and io: quick sanity glances. free near zero plus large cache is normal Linux (see free — "empty RAM is wasted RAM"); huge bi/bo means heavy block I/O, and if you want per-device detail you switch to iostat -xz 2.
That's the read: r/b, then si/so, then cpu, then cs, then a sanity glance. It tells you which subsystem to investigate, and then you reach for the specialist.
The Columns, Explained
Every column in vmstat, in the order they appear, by group.
procs — the run-queue group.
r— runnable processes (running on a CPU or waiting in the run queue for one). Compare to core count fromnproc. Steadyr > cores= CPU-bound queue.b— processes in uninterruptible sleep, blocked on I/O. Same asD-state intopandps. Highbwith idle CPU = the I/O subsystem is your bottleneck.
memory — the state group (snapshot, not rate).
swpd— total swap in use, KiB. Non-zero is fine and normal. Watch the trend, not the value.free— completely-unused RAM, KiB. Almost always small on a healthy box, and that's correct — seefree's "Linux ate my RAM" section.buff— RAM used as filesystem-metadata buffers. Usually small.cache— RAM used as the page cache. Usually the biggest number on the line. Reclaimable on demand.
swap — the rate group (this is where the alarm lives).
si— kibibytes per second swapped in from disk to RAM. Non-zero sustained = real pain.so— kibibytes per second swapped out from RAM to disk. Same alarm.
io — block-device aggregate.
bi— KiB/s read from block devices (block-in).bo— KiB/s written to block devices (block-out). For per-disk detail, switch toiostat -xz 2.
system — kernel work pulse.
in— interrupts per second, including the timer tick. A bored box reads a few hundred; a busy network or storage server can read tens of thousands.cs— context switches per second. The hidden performance metric. Tens of thousands = pathological.
cpu — same percentages as top's %Cpu(s) line.
us— user-mode CPU (your programs).sy— kernel-mode CPU (system calls on your behalf).id— idle.wa— I/O wait. The "busy waiting" bucket — the CPU is stalled on the disk. Highwa→ runiostat.st— stolen by the hypervisor. Cloud-VM signal that a noisy neighbour is sharing your physical host.gu— running KVM guest code (on hypervisor hosts only). Newer kernels.
Reading It by Example
A few patterns and what they each mean. Assume the rows below are rolling samples (you've already ignored the since-boot first row).
r=0 b=0, si=0 so=0, us=2 sy=1 id=97 — boring. The box is asleep. Move on.
r=12 b=0 on a 4-core box, us=85 sy=10 id=5 — CPU-bound. Twelve processes want four cores; queue depth is 8. Reach for top, press 1 to confirm it's actually using all cores, and find the hot process.
r=1 b=8, us=2 sy=3 id=20 wa=75 — disk-bound. One process running, eight blocked on I/O, three-quarters of CPU time spent waiting for the disk. Next command is iostat -xz 2 to see which device is saturated, then iotop to see which process is hammering it.
si=4096 so=8192 for three samples in a row — actively thrashing. The box is reading 4 MiB/s and writing 8 MiB/s of memory pages through the swap device. Performance is on the floor. Find the memory hog with ps aux --sort=-%mem | head, then either kill it, tune it down, or add RAM. This is the alarm free cannot show you — it knows swap is used, but only vmstat shows it being churned.
cs=85000, us=15 sy=20 id=65 — context-switch storm. CPU looks fine, memory fine, disk fine — but the box feels slow. Classic over-threaded application: thousands of threads waking each other on a lock. Check thread counts with ps -eLf | wc -l, find the offender with top -H or htop, and fix the app. No bigger server will help.
st=25 on a cloud VM — a noisy neighbour. Your VM is asking for CPU, the hypervisor is giving 25% of it to someone else. Not your fault; cloud-provider's overcommit. Complain, resize, or move.
r=0 b=0, but wa=40 and bi=80000 — a big sequential read is in flight. Maybe a backup, a dd, a database scan. CPU is waiting on the disk but no processes are queued — the I/O is just slow. Confirm with iotop.
Cheat Sheet
The invocations worth memorizing:
vmstat 2— sample every 2 seconds, forever.Ctrl-Cto quit.vmstat 2 5— sample every 2 seconds, five times, then exit.vmstat -y 2 5— same, but skip the since-boot first row. The version you want in scripts.vmstat -S M 2— units in mebibytes instead of kibibytes (memory and swap columns;bi/bostay in blocks).vmstat -w 2— wide format, doesn't collapse columns on memory-heavy boxes. Use on anything with more than 64 GiB.vmstat -a 2— replacesbuff/cachewithinact/activememory (the kernel's "recently used" split).vmstat -t 2— appends a timestamp to each line. Essential for logged output.vmstat -d— per-disk I/O statistics (a one-shot table, not a rolling sample). Overlaps withiostat.vmstat -D— summary of disk events since boot (total reads, writes, IOs).vmstat -p /dev/sda1— stats for one partition.vmstat -s— a long vertical dump of kernel counters, since boot. Useful forgrep-ing one specific stat.vmstat -f— totalfork()count since boot. Diagnostic for fork-storm bugs.vmstat -m— slabinfo (kernel data-structure caches). Niche.vmstat -n— print the column header only once instead of every screen-full. Good when piping toless.
How You'll Actually Use It
Three places, in practice. First, the triage glance: vmstat 2 5, ignore row one, eyes scan left to right across the rolling rows. Five seconds of sampling tells you which subsystem to investigate next — and that's the whole job. You won't stay in vmstat; you'll move to top for processes, free for memory detail, iostat for per-disk I/O, mpstat for per-core CPU. vmstat is the dispatcher.
Second, the logged sample: vmstat -y -t 60 >> /var/log/vmstat.log started in a tmux pane or under systemd gives you a one-line-per-minute history of the whole machine for the price of one disk write per minute. Cheap as dirt, and when something goes wrong overnight you have the rolling samples to read back. (For proper historical tracking with rotation and queries, install sar from the sysstat package — sar is essentially vmstat + iostat with on-disk storage.)
Third, the swap-thrashing confirmation: every time free shows worrying swap usage, the answer to "is it actually a problem?" is vmstat 1 and a look at si/so. Zero means swap is just parking cold pages; non-zero on every row means real thrashing. That single check resolves more "is this box dying?" questions than anything else in this article.
Gotchas
- The first row is the average since boot — almost always misleading. A box up for a month shows a smoothed lie. Always ignore row one, or use
-yto suppress it. vmstataggregates across all CPUs. The CPU columns are whole-machine percentages. One pinned core on a 16-core box reads as~6% ushere — invisible. Usempstat -P ALL 2ortopwith1pressed for per-core.bi/boare in blocks, not the unit you set with-S. A block is 1024 bytes on Linux (1 KiB), so the numbers look like KiB/s in practice — but-S Mdoes not convert them. The man page says so plainly; most people miss it.swpd > 0is not an alarm. Used swap is normal Linux behaviour. The alarm issi/so > 0sustained. Don't conflate them — seefree's gotchas for the long version.rincludes the currently-running processes too, not just the waiters. So on a 4-core box doing real work,r=4is full but healthy, not "queueing 4 deep."b(uninterruptible sleep) processes survivekill -9. Same trap asDintop/ps. A pile ofbmeans the I/O subsystem itself is stuck — fixing the storage / network mount is the cure, not killing processes.strequires a recent-enough kernel and a virtualised host. On bare metal it's always zero. On older kernels it didn't exist.- The columns shift between distros and versions (newer kernels added
gu). Don'tawk '{print $14}'againstvmstat— pin to header names, or usesar/ read/proc/statdirectly.
History & Philosophy
vmstat is one of the oldest "one screen, whole system" tools in UNIX. It predates top, it predates iostat as a separate utility, and the column layout you're reading today has been essentially stable for thirty years. It came out of BSD in the early 1980s — the same procps lineage as ps, free, uptime, and top — solving the question every operator has always had: give me one line that summarises the entire machine. The answer turned out to be six subsystems, sixteen columns, and a sample interval. The abstraction was right the first time, which is why nothing has replaced it.
And the secret that makes this whole tool click is the same one top, ps, and free reveal: vmstat isn't doing anything magic — it reads /proc. Specifically /proc/stat for the CPU and interrupt counters, /proc/meminfo for memory and swap state, /proc/vmstat for the swap-in/swap-out and paging counters, /proc/diskstats for bi/bo. The kernel publishes the entire live state of the machine as plain-text files; vmstat reads them twice, diffs the counters across your sample interval, divides by the interval to get rates, and prints. Two hundred lines of C. That's the "everything is a file" idea again — and once it lands, the urge to write your own little dashboards from /proc becomes irresistible.
Column Reference
All sixteen columns at a glance, grouped by the six subsystems they belong to:
| Group | Column | Meaning |
|---|---|---|
procs |
r |
Runnable processes (running or queued for a CPU) |
procs |
b |
Processes blocked in uninterruptible sleep on I/O |
memory |
swpd |
Total swap in use, KiB (snapshot) |
memory |
free |
Completely-unused RAM, KiB |
memory |
buff |
RAM used as filesystem-metadata buffers |
memory |
cache |
RAM used as the page cache |
swap |
si |
KiB/s swapped in from disk to RAM |
swap |
so |
KiB/s swapped out from RAM to disk |
io |
bi |
Blocks/s read from block devices |
io |
bo |
Blocks/s written to block devices |
system |
in |
Interrupts per second (includes the timer tick) |
system |
cs |
Context switches per second |
cpu |
us |
User-mode CPU (your programs) |
cpu |
sy |
Kernel-mode CPU (system calls) |
cpu |
id |
Idle |
cpu |
wa |
I/O wait — CPU stalled on the disk |
cpu |
st |
Stolen by the hypervisor |
See Also
- top — process-level view; reach for it once
vmstattells you CPU or memory - free — memory state in detail;
vmstat'ssi/sois the rate version offree's swap row - iostat — per-disk I/O; reach for it when
vmstat'swaorbi/bois high - mpstat — per-core CPU breakdown;
vmstataggregates,mpstatsplits - ps — snapshot of every process; find the culprit
vmstatonly hinted at - htop — interactive process explorer; nice complement to
vmstat - sar — historical version of
vmstat+iostat, from thesysstatpackage - /proc — where every number
vmstatprints actually lives - swap — what
si/soare actually moving in and out - memory — the full memory picture behind
free/buff/cache - kernel — what
sytime andin/csare counting - process — what
randbare counting - block device — what
bi/boare moving - thrashing — the problem
si/so > 0is announcing
Want to know which subsystem is hurting without squinting at sixteen columns?
CleverUptime reads
vmstat,iostat, and/procevery minute on every server and tells you in plain language ("swap-in 4 MiB/s sustained —mysqldis thrashing, not just using swap"), so the dashboard does the dispatching for you.Want to see your own server's health right now? One command, no signup, no install.