Skip to content
Dev Tools Article

Beyond the Colors: A Developer's Guide to htop

Stop treating your process monitor as a passive dashboard and start using it to diagnose real-world performance bottlenecks.

Rachel Goldstein
Rachel Goldstein
Dev Tools Editor · Jul 4, 2026 · 6 min read
Beyond the Colors: A Developer's Guide to htop

We have all been there. You SSH into a sluggish production box, type htop, and stare at a wall of red, green, and yellow bars. It looks impressive, but what is it actually telling you?

Many developers treat htop as a passive dashboard, a quick way to see if the server is melting. They see a high load average, panic, and immediately try to throw more hardware at the problem. But if you do not understand the underlying kernel abstractions, you are just guessing. To use htop effectively for real-world debugging, you have to understand the /proc filesystem interfaces it exposes, the math behind load averages, and the differences between virtual, resident, and shared memory.

Demystifying the Header: Uptime and Load Averages

At the very top of the htop interface, you will find system uptime and load averages. These are not calculated by htop itself. Instead, htop reads them directly from the /proc directory, the kernel's virtual filesystem.

If you run strace uptime, you will see that the system opens /proc/uptime and /proc/loadavg to fetch this data. You can inspect these files yourself:

$ cat /proc/uptime
9592411.58 9566042.33

The first number is the total uptime of the system in seconds. The second number is the cumulative idle time, in seconds, across all cores. Because the idle time is a sum across all cores, it can easily exceed the total uptime on multi-core systems.

Right next to uptime are the three load average numbers. A common misconception is that a load average of 1.0 on a single-core machine means 100% CPU utilization. That is not quite right.

$ cat /proc/loadavg
0.00 0.01 0.03 1/120 1500

The first three columns represent the system load over the last 1, 5, and 15 minutes. The fourth column shows the number of currently running or runnable processes over the total number of processes (e.g., 1/120 means one process is currently running or ready to run, while 120 exist in total). The final column is the last process ID (PID) allocated by the system.

But what does that load number actually mean? It is not a simple arithmetic average. It is an exponentially damped moving average. Mathematically, the 1-minute load average incorporates 63% of the load from the past 60 seconds and 37% of the load from the system's history prior to that minute.

More importantly, the load number counts processes in two states:

  1. Runnable processes: Those currently using the CPU or waiting in the run queue for their turn.
  2. Uninterruptible processes: Those waiting for disk I/O, network activity, or some other hardware event (often marked as state D in process lists).

This distinction is critical. If your database server has a load average of 20 on an 8-core machine, but your CPU utilization is sitting at 5%, you do not have a CPU bottleneck. You have an I/O bottleneck. Your processes are piling up while waiting for a slow disk or a hung network share.

The Memory Matrix: VIRT vs. RES vs. SHR

When looking at the process list in htop, the memory columns often cause unnecessary panic. Developers see a process with a massive virtual memory size and assume it is leaking. To diagnose memory issues, you must understand the three distinct memory metrics:

  • VIRT (Virtual Memory): This is the total address space the process has mapped. It includes physical RAM, swapped-out memory, mapped files on disk (like shared libraries), and memory that the process has allocated but not yet written to. Modern runtimes like Java or Go often pre-allocate massive virtual address spaces. A high VIRT value is rarely a cause for concern.
  • RES (Resident Memory): This is the actual physical RAM the process is consuming right now. If you are worried about running out of physical memory or getting hit by the Out-Of-Memory (OOM) killer, this is the column to watch.
  • SHR (Shared Memory): This represents memory that could be shared with other processes. For example, if multiple processes load the same shared C library, that memory is counted under SHR for each process, but it only exists once in physical RAM.

The Swap Myth

Another point of confusion is the Swp (Swap) bar. You might notice your system using swap space even when there is plenty of physical RAM available. This is controlled by the Linux kernel's swappiness parameter.

By default, the kernel will proactively swap out idle, inactive process memory to disk so it can use that freed physical RAM for disk caching. Disk caching speeds up file reads, which is often a better use of fast physical RAM than keeping a dormant background daemon in memory. Swap usage is not inherently a sign of resource exhaustion; it is often just the kernel doing its job.

CPU Metrics: Irix vs. Solaris Mode

When looking at CPU usage in htop, you might see a single process showing a CPU usage of 400%. This happens because htop defaults to "Irix mode," where CPU usage is calculated as a percentage of a single CPU core. If a multi-threaded process is fully utilizing four cores, it will show 400% CPU usage.

If you prefer to see CPU usage normalized by the total number of cores in your system, you can toggle this behavior. According to the man7.org manual page, this normalized view is sometimes called "Solaris mode" or PERCENT_NORM_CPU. In this mode, a process utilizing four cores on an eight-core machine will show 50% CPU usage instead of 400%.

The Interactive Debugging Workflow

Most developers use htop as a read-only tool, but its real power lies in its interactive features. Instead of copying PIDs to run separate commands, you can perform complex diagnostics directly from the interface.

1. Isolate and Filter

Instead of scrolling through hundreds of database worker processes, use the built-in filtering tools:

  • Press F4 to filter the process list by name (e.g., type postgres or node).
  • Use the -u flag on startup to only show processes owned by a specific user: htop -u www-data.
  • Use the -p flag to monitor specific PIDs: htop -p 1024,2048.

2. Visualize Process Hierarchies

Pressing F5 toggles the tree view. This is incredibly useful for understanding parent-child relationships. If you are running a clustered application server (like Puma, Unicorn, or Gunicorn), the tree view lets you easily distinguish the master process from its spawned worker processes.

3. Trace System Calls on the Fly

If a process is hung and you do not know why, you do not need to drop out of htop to run strace. Simply highlight the problematic process and press s.

This will launch a real-time trace of all system calls the process is making. If you see the process blocked on a read system call, you know it is waiting on network or disk input. If you see a rapid fire of epoll_wait calls, it is actively polling for network events.

4. Manage Priorities and Signals

You can adjust process priorities (the "nice" value) directly inside htop. Highlighting a process and pressing F7 increases its priority (decreases its nice value), while F8 decreases it.

When a process needs to be terminated, do not default to kill -9. Press F9 to open the signal menu. This allows you to send a graceful SIGTERM (15) first, giving the process a chance to clean up resources and close database connections, before resorting to a destructive SIGKILL (9).

Making htop Cheaper to Run

By default, htop refreshes its data frequently, which can consume non-trivial CPU cycles on a system that is already struggling. If you are logging into a heavily loaded server, you should reduce the update frequency.

You can set the delay interval using the -d flag, which accepts values in tenths of a second. Running htop -d 30 configures a 3-second delay, drastically reducing htop's own resource footprint while you investigate the system's health.

Sources & further reading

  1. Explanation of everything you can see in htop/top on Linux — peteris.rocks
  2. htop Explained Visually | CodeAhoy — codeahoy.com
  3. An explanation of everything you can see in htop/top on Linux — changelog.com
  4. What is htop and What Does It Do? [htop Command] — monovm.com
  5. htop Command in Linux - GeeksforGeeks — geeksforgeeks.org
Rachel Goldstein
Written by
Rachel Goldstein · Dev Tools Editor

Rachel has been embedded in the developer tooling ecosystem for nearly eight years, covering everything from IDE wars and package-manager drama to the quiet rise of AI-assisted coding. She has a soft spot for open-source maintainers and an unhealthy number of terminal emulators installed on a single laptop.

Discussion 5

Join the discussion

Sign in or create an account to comment and vote.

Jen Okafor @rustacean_jen · 1 month ago

i love how this article highlights the importance of understanding the underlying system abstractions - it's so similar to how rust's ownership model helps you think about memory safety, by making you consider the actual resources your code is using

Brianna Cole @burned_out_bri · 1 month ago

@rustacean_jen so true, wish i'd learned that sooner, would've saved me so much trouble

Will Carter @weekend_warrior_will · 1 month ago

totally with you on that @burned_out_bri, i've lost count of how many times i've spun my wheels trying to optimize the wrong thing, gonna have to dive deeper into those /proc filesystem interfaces this weekend

Pia Andersson @promptsmith_pia · 1 month ago

totally agree with you @rustacean_jen, understanding the system abstractions is key - i've found that once you grasp how htop is using the /proc filesystem, it's like a whole new world of debugging opens up, and you can start to see how your code is actually impacting the system

Marco Bianchi @shipfast_marco · 1 month ago

i'm with you @promptsmith_pia, once you understand what's under the hood, htop goes from pretty colors to a serious debugging tool - we've used it to catch some crazy memory leaks in our startup's code, shipped a fix and it was night and day

Related Reading