When something on my server starts acting up — load average creeping up, a process eating memory it has no business eating — top is the very first tool I reach for. It’s been part of Linux (and Unix before it) for decades, and even with newer tools like htop and btop around, I still find myself typing top out of pure muscle memory. In this guide I’m going to walk through everything I know about top: how it works, what every column actually means, how to read it correctly under pressure, and how I use it in real troubleshooting sessions.
What is the top Command?
top stands for “table of processes.” It’s a real-time, interactive process viewer that shows a live, auto-refreshing snapshot of what’s running on a Linux system — CPU usage, memory usage, process states, and more. Unlike ps, which gives you a single static snapshot, top keeps updating on its own (every 3 seconds by default), which makes it perfect for watching a system’s behavior as it happens.
top is part of the procps (or procps-ng on modern distros) package, and it reads its data directly from the /proc virtual filesystem — a special filesystem the Linux kernel exposes that represents running processes and system state as files. Every time top refreshes, it’s re-reading files like /proc/[pid]/stat, /proc/meminfo, and /proc/loadavg.
Basic Syntax
top [options]
When you run top with no options, it launches an interactive full-screen session in your terminal that updates continuously until you press q to quit.
Understanding the top Output
Let me break down a real output I captured on a test machine:
top - 01:37:04 up 0 min, 0 user, load average: 0.16, 0.03, 0.01
Tasks: 61 total, 1 running, 60 sleeping, 0 stopped, 0 zombie
%Cpu(s): 7.7 us, 15.4 sy, 0.0 ni, 76.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 3998.0 total, 3897.3 free, 197.2 used, 45.9 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 3800.8 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 15164 5440 2724 S 0.0 0.1 0:00.59 process_a+
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
Line 1: The Summary Line
top - 01:37:04 up 0 min, 0 user, load average: 0.16, 0.03, 0.01
- 01:37:04 — current time
- up 0 min — system uptime
- 0 user — number of logged-in users
- load average: 0.16, 0.03, 0.01 — this is one of the most important numbers on the whole screen. It shows the average number of processes waiting for CPU time over the last 1, 5, and 15 minutes. On a single-core system, a load average of 1.0 means the CPU is fully saturated. On a 4-core system, you’d want to see this stay below 4.0 before things start queuing up.
Line 2: Task Summary
Tasks: 61 total, 1 running, 60 sleeping, 0 stopped, 0 zombie
This tells me exactly how many processes exist and what state they’re in:
- running — actively executing on a CPU right now
- sleeping — waiting for something (I/O, a timer, a signal)
- stopped — paused, usually via a signal like
SIGSTOP - zombie — a process that has finished but whose parent hasn’t yet collected its exit status via
wait(). A handful of zombies briefly is normal; hundreds of them piling up usually means a buggy parent process isn’t reaping its children.
Line 3: CPU Usage Breakdown
%Cpu(s): 7.7 us, 15.4 sy, 0.0 ni, 76.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
This is the line I check first on any performance issue:
| Field | Meaning |
|---|---|
us | Time spent running user-space processes |
sy | Time spent in the kernel (system calls, syscalls, drivers) |
ni | Time spent running processes with a manually adjusted “nice” priority |
id | Idle time — the CPU doing nothing |
wa | I/O wait — CPU idle while waiting on disk or network I/O |
hi | Time servicing hardware interrupts |
si | Time servicing software interrupts |
st | “Steal” time — time a virtual CPU waited for a physical CPU while the hypervisor served another VM |
If I see wa climbing high, I know I’m looking at a disk bottleneck, not a CPU one. If st is high, the physical host running my VM is oversubscribed.
Lines 4–5: Memory
MiB Mem : 3998.0 total, 3897.3 free, 197.2 used, 45.9 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 3800.8 avail Mem
- total — total installed RAM
- free — completely unused memory
- used — memory actively in use by processes
- buff/cache — memory used for disk buffers and page cache (this is reclaimable, so don’t panic if it’s high)
- avail Mem — the number that actually matters: how much memory is available for new processes, accounting for reclaimable cache
I never judge memory pressure from “free” alone. A Linux box with almost no “free” memory but a huge “buff/cache” is healthy — the kernel is just using spare RAM to cache files, and it’ll release that instantly if an application needs it.
The Process Table
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- PID — process ID
- USER — the owner of the process
- PR — scheduling priority as seen by the kernel
- NI — the “nice” value (-20 to 19; lower means higher priority)
- VIRT — total virtual memory used (includes mapped-but-unused memory)
- RES — resident memory — the actual physical RAM the process is using right now (this is the number I actually care about)
- SHR — shared memory (libraries shared with other processes)
- S — process state:
Rrunning,Ssleeping,Duninterruptible sleep (usually I/O),Tstopped,Zzombie - %CPU / %MEM — percentage of CPU/memory usage
- TIME+ — cumulative CPU time consumed
- COMMAND — the process name or command line
Common top Parameters
| Option | Description |
|---|---|
-d <seconds> | Set the refresh delay (default 3 seconds) |
-n <number> | Exit after a given number of updates — great for scripting |
-b | Batch mode — prints output continuously without the interactive UI, ideal for logging or piping |
-p <pid,pid,...> | Monitor only specific process IDs |
-u <user> | Show only processes owned by a specific user |
-i | Hide idle/zombie processes |
-H | Show individual threads instead of summarizing per process |
-o <field> | Sort by a specific field on startup |
-1 | Show individual CPU core usage instead of an aggregate |
Example: One-shot batch snapshot for logging
top -bn1 > /var/log/top-snapshot.log
I use this constantly in cron jobs and monitoring scripts — -b disables the interactive screen so the output can be redirected cleanly, and -n1 tells it to stop after one iteration.
Example: Watching a specific process
top -p 1234
Example: Per-user view
top -u www-data
Example: Show per-core CPU stats
Inside an already-running top session, pressing 1 toggles between a combined CPU summary line and individual lines per core. This is essential on multi-core boxes where one runaway thread can peg a single core to 100% while overall usage looks fine.
Interactive Key Commands
Once top is running, these keystrokes change what you’re seeing without restarting it:
| Key | Action |
|---|---|
q | Quit |
h | Help |
k | Kill a process (prompts for PID and signal) |
r | Renice a process (change its priority) |
f | Choose/reorder which fields are displayed |
o | Change sort field |
M | Sort by memory usage |
P | Sort by CPU usage |
T | Sort by cumulative time |
c | Toggle full command line vs. short name |
1 | Toggle per-core CPU display |
z | Toggle color |
W | Save current settings to ~/.config/procps/toprc |
How top Works Internally
Every refresh cycle, top walks the /proc filesystem, reading a directory per process (/proc/1, /proc/2, and so on), each containing files like stat, status, statm, and cmdline. It computes CPU percentages by comparing CPU tick counters between two samples, dividing by the elapsed wall-clock time. That’s why the very first refresh after launching top can look inaccurate — it hasn’t collected a second sample to diff against yet.
Because top reads from /proc rather than making expensive syscalls per process, it’s relatively lightweight, though on a system with tens of thousands of processes, even walking /proc can add measurable overhead — which is one reason -b -n1 snapshots are gentler than leaving an interactive session open for hours.
Real-World Use Cases
Diagnosing a runaway process: I sort by %CPU (press P) or %MEM (press M) and immediately see the worst offender at the top of the list.
Investigating high load with low CPU usage: If load average is high but %Cpu(s) shows lots of idle time, I check the wa (I/O wait) column and cross-reference with iostat — usually a disk or network storage issue.
Watching a deploy: During a service restart or rolling deploy, I run top -p $(pgrep -d, myapp) to watch just my application’s processes as they come up and stabilize.
Finding memory leaks: I watch the RES column for a specific PID over time. Steadily climbing RES with no corresponding drop is a strong memory leak signal.
Troubleshooting With top
- High
%wa→ disk I/O bottleneck. Follow up withiostat -x 1oriotop. - High
%sy→ excessive kernel time, often from heavy syscalls, context switching, or a misbehaving driver. - High
%st→ the hypervisor is starving your VM of CPU cycles; talk to your cloud provider or check for noisy neighbors. - Zombie processes piling up → the parent process isn’t calling
wait(). Restart the parent or investigate the application code. - Load average high, CPU idle → check for processes in
Dstate (uninterruptible sleep), which usually means they’re blocked on I/O.
Performance Optimization Tips
- Use
-b -n1for logging instead of leaving an interactivetopopen — interactive sessions constantly repaint the terminal, which has real overhead over SSH. - Increase the refresh delay with
-d 5or higher on busy production boxes to reduce the sampling overheadtopitself introduces. - Prefer
-Hsparingly — showing every thread on a heavily multi-threaded application (like a JVM) can produce screens with thousands of rows.
Security Implications
top only shows processes the current user has permission to see details for, though on most Linux systems any user can see the process list of every other user (just not necessarily full command-line arguments if a process has hidden them). As root, top gives visibility into everything running on the box, including other users’ processes — which is exactly why access to a root shell is such a high-value target. When auditing a shared or multi-tenant system, I always check who has sudo rights to run top as root, since it exposes command lines that can sometimes leak secrets (e.g., a password passed as a CLI argument).
top vs. Related Commands
| Command | Difference from top |
|---|---|
htop | A more user-friendly, colorized, mouse-enabled alternative to top, with easier process tree view and killing. Not installed by default on all distros. |
ps | Static, single-snapshot process listing — great for scripting, but doesn’t auto-refresh. |
atop | Similar to top but logs historical data to disk, useful for post-incident analysis. |
glances | A cross-platform system monitor that combines CPU, memory, disk, and network stats in one dashboard. |
vmstat | Focuses specifically on virtual memory statistics rather than per-process detail. |
I still reach for plain top first because it’s guaranteed to be installed on virtually every Linux system I touch — htop isn’t always there, especially on minimal container images and stripped-down server installs.
Compatibility Across Distributions
top ships as part of procps-ng on Debian/Ubuntu, RHEL/CentOS/Fedora, and Arch. The core behavior is consistent everywhere, though minor differences exist:
- Older BusyBox-based systems (common in minimal containers and embedded Linux) include a much simpler
topwith fewer options. - macOS and BSD systems have their own
topimplementations with different flags and column layouts — commands you learn on Linux’stopwon’t directly transfer.
Summary
top remains one of the most fundamental diagnostic tools in Linux system administration. It gives me a live view into CPU, memory, and process behavior without needing to install anything extra, and its /proc-based design means it’s fast and reliable even under load. Understanding the load average, the CPU breakdown line, and the memory summary is the foundation for almost every performance investigation I do — everything else (iostat, vmstat, strace) builds on the picture top gives me first.
References
- GNU/Linux
procps-ngproject: https://gitlab.com/procps-ng/procps - Linux man-pages project,
top(1): https://man7.org/linux/man-pages/man1/top.1.html - The Linux Kernel
/procfilesystem documentation: https://www.kernel.org/doc/html/latest/filesystems/proc.html - Debian manpages: https://manpages.debian.org/