How to Monitor System Resources on Linux in Real Time
A practical toolkit for watching CPU, memory, disk, and network usage live — going beyond top to actually find what's causing a resource problem.
This walks through a practical, layered toolkit for real-time resource monitoring on Linux — starting with the tools everyone knows, then the ones that actually pinpoint which process or operation is responsible once a general tool has flagged a problem.
Step 1: get the overall picture with top or htop
top
htop
htop is generally a better starting point if available — a full-screen, color-coded, mouse-scrollable view of every process, sortable by CPU or memory with a keypress, versus top’s more limited default interface.
Step 2: identify which resource is actually under pressure
Before chasing a specific process, vmstat gives a fast, one-command overview of CPU, memory, and I/O pressure together:
vmstat 1
A high value in the wa (I/O wait) column points to disk contention; a high us/sy split points to CPU-bound work; a growing swpd alongside low free memory points to memory pressure.
Step 3: for CPU specifically, find the exact process
top -o %CPU
pidstat 1
pidstat (from the sysstat package) breaks CPU usage down per-process over time intervals, which is more useful than a single snapshot for catching a process that spikes intermittently rather than staying consistently busy.
Step 4: for memory, distinguish “used” from “cached”
free -h
total used free shared buff/cache available
Mem: 15Gi 3.2Gi 1.1Gi 412Mi 11Gi 11Gi
The buff/cache column is memory the kernel is using opportunistically for disk cache — it’s reclaimable on demand, not memory that’s actually unavailable to applications. The available column is the more accurate “how much can a new application actually get” figure; don’t judge memory pressure from free alone.
Step 5: for disk I/O, find which process and which device
iotop
iotop (similar to top, but for disk I/O specifically) shows exactly which process is reading or writing the most, live — the fastest way to identify a runaway log writer, a backup job, or a database doing an unexpected full scan.
Step 6: for network, watch bandwidth per connection
nload
ss -tnp
ss -tnp lists active TCP connections along with the owning process — useful for identifying which specific process holds an unexpected number of open connections, or an unusually high-bandwidth one.
Step 7: for a longer-term view, not just live snapshots
sar -u 1 10 # CPU, sampled every 1s, 10 times
sar -r 1 10 # memory
sar -d 1 10 # disk
sar, also from sysstat, is what you reach for when you need to look back at resource usage from ten minutes ago rather than only observing live — provided the sysstat collection service was already running, which is worth enabling proactively on any server you’ll need to debug later:
systemctl enable --now sysstat
Step 8: tie it together for a specific misbehaving process
Once top/htop has identified a specific suspicious PID, pidstat, strace -c -p <pid> (a syscall-frequency summary), and reading /proc/<pid>/status and /proc/<pid>/io directly give you a detailed, process-specific picture without needing any additional tooling beyond what’s already on the system.
Building the right habit
The practical workflow that ties all of this together: start broad (vmstat/htop) to identify which resource is under pressure, then reach for the resource-specific tool (pidstat for CPU, iotop for disk, ss/nload for network) to find the specific process responsible, rather than staring at one general-purpose tool and hoping the answer becomes obvious. Enabling sysstat proactively, before you need it, is the one step worth doing on every server ahead of time — historical data is what turns “something was slow at 3am” into an actual, diagnosable event instead of a shrug.