What a Process Is
Every running program is a process with a unique PID (process ID), an owner, and a parent that started it. Everything descends from PID 1 (systemd). When a server "feels slow," the answer is almost always hiding in the process list — the skill is knowing how to read it.
ps aux → every process, one snapshot ps aux | grep nginx → find a specific one ps aux --sort=-%mem | head → top 10 memory hogs ps -ef --forest → tree view: who started what pgrep -a node → PIDs + command line by name
Reading ps aux columns: %CPU and %MEM are self-explanatory; VSZ/RSS are virtual vs actual memory; STAT shows state — S sleeping (normal), R running, Z zombie, D stuck waiting on disk/network (a column full of D usually means storage trouble).
Live Views: top and htop
top is on every box; htop (one apt install away) adds color, scrolling, and mouse support. Inside top: M sorts by memory, P by CPU, k kills, q quits.
# The line that matters most in top: load average: 0.42, 0.51, 0.60 # 1min 5min 15min # Rule of thumb: load ≈ number of CPU cores = fully busy. # 4.0 on a 4-core box is saturated; on a 16-core box it's idle chatter. nproc → how many cores do I have?
High load with low CPU% means processes are waiting on disk or network, not compute — check iostat or that D-state column before blaming the CPU.
Memory: Reading free Correctly
free -h # total used free buff/cache available # Mem: 7.8G 2.1G 0.4G 5.3G 5.4G # "free" being tiny is FINE — Linux uses idle RAM as disk cache # and gives it back instantly. The number that matters: "available".
If available approaches zero, the kernel's OOM killer starts executing your largest processes — check journalctl -k | grep -i oom when a service mysteriously vanished overnight.
Stopping Processes: Signals
kill doesn't kill — it sends a signal. The polite one asks the process to shut down cleanly; the last resort yanks it with no chance to save state. Always escalate in order:
kill 1234 → SIGTERM: "please exit cleanly" (default) kill -9 1234 → SIGKILL: immediate, no cleanup — last resort kill -HUP 1234 → many daemons reload config on this pkill -f "python.*stuck_script" → kill by command-line match # For anything managed by systemd, prefer: systemctl stop myapp → lets systemd track the state
Why not always -9? SIGKILL skips cleanup — half-written files, orphaned lock files, un-flushed databases. If a process ignores SIGTERM for 30 seconds, then escalate.
The 5-Minute "Why Is It Slow?" Routine
# 1. Overall pressure — load vs core count uptime && nproc # 2. Who's eating CPU / RAM? ps aux --sort=-%cpu | head -6 ps aux --sort=-%mem | head -6 # 3. Memory actually available? free -h # 4. Disk full? (a 100% root filesystem breaks everything weirdly) df -h # 5. Anything crash-looping or waiting on I/O? systemctl list-units --failed journalctl -p err --since "1 hour ago" --no-pager | tail -20
This routine answers 90% of "the server is acting weird" incidents before you ever need real monitoring — and when you outgrow it, that's your cue for the Prometheus + Grafana guide in the Guides section.
≈·*•—[ A|S ]—•*·≈