Process Management
Understanding processes separates people who can debug a stuck system from people who just reboot it. Everything running on a Unix box is a process — it has a PID, an owner, a parent, a working directory, and a set of open file descriptors. Once you can see that structure clearly, a lot of mysterious system behaviour starts making sense.
What's Running
$ ps aux # all processes, BSD-style flags (most commonly used) $ ps -ef # all processes, POSIX-style $ ps aux | grep nginx # find processes matching a name $ pgrep -l nginx # cleaner: list PIDs and names matching "nginx" $ pidof nginx # just the PIDs
Process State Codes
The STAT column in ps aux output tells you what the process is doing:
| Code | State | Notes |
|---|---|---|
| R | Running or runnable | Actively using or waiting for CPU |
| S | Sleeping | Waiting for I/O, a signal, or a timer — normal |
| D | Uninterruptible sleep | Waiting on I/O — cannot be killed; usually a disk or NFS problem |
| Z | Zombie | Finished but parent hasn't collected its exit status |
| T | Stopped | Paused (SIGSTOP or Ctrl+Z) |
Processes in state D (uninterruptible sleep) are typically stuck on a dying disk or an unresponsive network filesystem. kill -9 won't work on them — you often have to reboot.
Process Hierarchy
$ pstree -p # full process tree with PIDs $ ps -o pid,ppid,cmd # show PID and parent PID for every process
Every process has a parent. PID 1 (systemd or init) is the ancestor of everything. When you run a command from a shell, the shell forks a child to run it. Understanding parent-child relationships helps when you're trying to figure out why a process keeps restarting — something is respawning it.
Signals
Signals are how you communicate with a running process. Most people only know kill -9, which is the sledgehammer — it works but the process has no chance to clean up:
| Signal | Number | Meaning | Can be caught? |
|---|---|---|---|
| SIGTERM | 15 | Polite termination — process can handle it and clean up | Yes |
| SIGKILL | 9 | Force kill — cannot be caught or ignored | No |
| SIGHUP | 1 | Hangup — daemons traditionally reload config on SIGHUP | Yes |
| SIGSTOP | 19/17 | Pause a process (like Ctrl+Z) | No |
| SIGCONT | 18/19 | Resume a paused process | Yes |
| SIGINT | 2 | Interrupt (Ctrl+C in terminal) | Yes |
$ kill -SIGTERM 1234 # or: kill -15 1234 $ kill -SIGKILL 1234 # or: kill -9 1234 $ kill -SIGHUP 1234 # reload config (nginx, apache, etc.) $ pkill nginx # kill by name $ pkill -HUP nginx # send HUP to all processes named nginx $ killall firefox # kill all processes with this exact name
Best practice: try SIGTERM first, wait a few seconds, then SIGKILL if the process doesn't exit. Most well-written daemons handle SIGTERM gracefully.
Job Control
Job control lets you manage multiple things in a single shell session:
$ long_command & # run immediately in background $ long_command ^Z # Ctrl+Z suspends the foreground process $ bg # continue suspended job in background $ fg # bring the most recent background job to foreground $ fg %2 # bring job 2 to foreground specifically $ jobs # list all jobs in current session
# Survive session logout: $ nohup ./myscript.sh & # immune to hangup; output goes to nohup.out $ disown %1 # detach job 1 from the shell (no nohup file) # Better: use tmux or screen for long-running sessions $ tmux new -s mysession # start a named tmux session $ tmux attach -t mysession # reattach after disconnecting
Finding What's Using a Resource
# What's using a port? $ lsof -i :8080 $ ss -tlnp | grep 8080 # What process has this file open? $ lsof /var/log/app.log # What's blocking an unmount? $ fuser /mnt/usb # shows PIDs using the mount $ fuser -k /mnt/usb # kill all processes using it # What files does a process have open? $ lsof -p 1234
Process Priority: nice and renice
Nice values range from -20 (highest priority, hogs CPU) to 19 (lowest, yields to everything). Regular users can only lower priority (raise the nice value). Root can raise priority:
$ nice -n 10 ./heavy_job.sh # start with lower priority (nice 10) $ renice +10 -p 1234 # lower priority of a running process $ renice -5 -p 1234 # raise priority (needs root) $ renice +15 $(pgrep ffmpeg) # lower priority of all ffmpeg processes
Monitoring Over Time
| Command | Shows | Notes |
|---|---|---|
top | Live CPU/memory by process | Press 1 to see per-CPU, M to sort by memory |
htop | Same but friendlier | Tree view, mouse support, colour coding |
vmstat 1 | System-wide stats every second | Good for spotting memory pressure (swap activity) |
iostat -x 1 | Per-device I/O stats every second | %util column shows if a disk is saturated |
sar -u 1 10 | CPU usage, 10 samples | Part of sysstat package |
When a system is slow, the sequence: check top for CPU/memory hogs → check iostat to see if it's I/O-bound → check lsof if a specific process seems to be holding resources.
dispelled