Skip to content

Process Management

Every running program on Linux is a process with a unique PID (process ID). This page covers how to view processes, find them, send them signals, change their priority, control background jobs, and read system load.

Tested on

AlmaLinux 9.4 and Ubuntu 22.04 LTS. The tools here are identical across distributions; htop may need installing (sudo dnf install htop after enabling EPEL, or sudo apt install htop).

Processes, PIDs, and the process tree

  • Each process has a PID and a PPID (parent PID). Processes form a tree: a parent spawns children with fork().
  • PID 1 is the first process started by the kernel — on modern systems that's systemd. It is the ultimate ancestor of everything.
  • When a parent dies before its child, the child is re-parented to PID 1.
  • For managing long-running services, you usually want systemd rather than raw process tools — see systemd Service Management. The tools below are for ad-hoc inspection and control.

Viewing processes

ps — a snapshot

ps prints a one-time snapshot. Two classic flag styles:

# BSD style: every process, with CPU/memory and the controlling user
ps aux

# UNIX style: every process in full format with PPID
ps -ef
USER       PID %CPU %MEM    VSZ   RSS TTY  STAT START   TIME COMMAND
root         1  0.0  0.1 172412 13720 ?    Ss   09:01   0:02 /usr/lib/systemd/systemd
root       742  0.0  0.0  82940  3204 ?    Ss   09:01   0:00 /usr/sbin/sshd -D
nginx     1190  0.1  0.4 145320 17880 ?    S    09:05   0:01 nginx: worker process

Key ps aux columns: PID, %CPU, %MEM, RSS (resident memory in KB), STAT (state: S=sleeping, R=running, Z=zombie, D=uninterruptible), and COMMAND.

# Filter to one program
ps aux | grep '[s]shd'

# Sort by memory or CPU usage (top consumers last)
ps aux --sort=-%mem | head
ps aux --sort=-%cpu | head

pstree — the hierarchy

# Show the process tree with PIDs
pstree -p

# Tree for one user
pstree -p nginx

top and htop — live view

top

In top: press M to sort by memory, P by CPU, k to kill a PID, 1 to show per-core CPU, q to quit.

htop is a friendlier, colorized alternative with mouse support, scrolling, and easy tree view (F5):

htop

Finding processes

# Get the PID(s) of a named program
pidof sshd
pgrep sshd            # also matches by pattern

# pgrep with more context
pgrep -a nginx        # show full command line too
pgrep -u nginx        # processes owned by user 'nginx'
pgrep -f 'python.*app.py'   # match against the full command line
# pidof sshd
742 1503

Signals and termination

You control processes by sending signals. kill despite its name just sends a signal — the default is SIGTERM.

# Politely ask a process to terminate (SIGTERM, signal 15)
kill 1190
kill -TERM 1190        # explicit, same thing

# Force kill — cannot be caught or ignored (SIGKILL, signal 9)
kill -9 1190
kill -KILL 1190

# Tell a process to reload its config (SIGHUP, signal 1)
kill -HUP 742

By name instead of PID:

# killall: match by exact process name
killall nginx
killall -9 nginx

# pkill: match by pattern (like pgrep)
pkill -f 'python.*app.py'
pkill -u baduser           # kill all of a user's processes

Common signals

Signal Number Default action Use
SIGHUP 1 Terminate Hang-up; many daemons reload config on it
SIGINT 2 Terminate What Ctrl-C sends
SIGQUIT 3 Terminate + core dump Ctrl-\
SIGKILL 9 Terminate (uncatchable) Last resort — process cannot clean up
SIGTERM 15 Terminate Default, graceful shutdown request
SIGSTOP 19 Stop (uncatchable) Pause a process
SIGCONT 18 Continue Resume a stopped process
SIGTSTP 20 Stop What Ctrl-Z sends

SIGTERM before SIGKILL

Always try SIGTERM (kill PID) first. It lets the program flush buffers, close files, and exit cleanly. SIGKILL (-9) is brutal — the kernel destroys the process immediately, which can corrupt files or leave stale locks. Only escalate to -9 if SIGTERM is ignored.

Zombies

A process in state Z (zombie/defunct) has already exited; it's just an entry waiting for its parent to "reap" it. You cannot kill a zombie — it's already dead. If they pile up, the parent process is buggy; restart or kill the parent.


Priorities: nice and renice

The kernel scheduler uses a niceness value from -20 (highest priority, greediest) to +19 (lowest priority, most generous to others). Default is 0. Lower number = more CPU.

# Start a command with a higher niceness (lower priority)
nice -n 10 ./batch-job.sh

# Start with higher priority (negative needs root)
sudo nice -n -5 ./latency-sensitive

# Change the niceness of a running process
renice -n 5 -p 1190

# Renice all processes of a user
sudo renice -n 10 -u baduser

Tip

Only root can assign negative niceness (raise priority). Regular users can only be "nicer" (raise the number, lower priority). Check a process's niceness in the NI column of top or ps -o pid,ni,comm.


Job control

When you run a command in a terminal it runs in the foreground, tying up your shell. Job control lets you push work to the background.

# Start a command in the background with &
long-running-task &

# List jobs in the current shell
jobs
[1]-  Running    long-running-task &
[2]+  Stopped    vim notes.txt
# Suspend the foreground process: press Ctrl-Z (sends SIGTSTP)

# Resume a stopped job in the background
bg %1

# Bring a job back to the foreground
fg %1

Surviving logout: nohup and disown

A background job still dies when you log out (it receives SIGHUP). To keep it running:

# nohup ignores SIGHUP and redirects output to nohup.out
nohup ./backup.sh &

# Or detach an already-running job from the shell
./backup.sh &
disown %1

Better: use systemd or tmux

For anything important, prefer a systemd service (see systemd Service Management) or a terminal multiplexer like tmux/screen. They survive disconnects far more reliably than nohup.


The /proc filesystem

/proc is a virtual filesystem exposing the kernel's view of every process and the system. Each PID has a directory /proc/<PID>/.

# What's the command line of PID 742?
cat /proc/742/cmdline | tr '\0' ' '; echo

# Environment, open files, current working directory of a process
sudo cat /proc/742/environ | tr '\0' '\n'
sudo ls -l /proc/742/fd
sudo ls -l /proc/742/cwd

# System-wide info
cat /proc/cpuinfo      # CPU details
cat /proc/meminfo      # memory details
cat /proc/loadavg      # load averages + running/total processes
uptime                 # friendlier loadavg view

Quick system load views

# Uptime and 1/5/15-minute load averages
uptime
 10:42:18 up 1 day,  1:41,  2 users,  load average: 0.18, 0.25, 0.21

A load average roughly equals the number of processes wanting CPU. Compare it to your core count: on a 4-core box, a load of 4.0 means fully busy; sustained above that means a backlog.

# Memory in human-readable units
free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       3.2Gi       8.1Gi       180Mi       4.1Gi        11Gi
Swap:          4.0Gi          0B       4.0Gi

Watch the available column, not free — Linux uses spare RAM for cache and reclaims it on demand.

# vmstat: refresh every 2 seconds, system-wide pressure view
vmstat 2

Watch r (run queue), si/so (swap in/out — nonzero means memory pressure), and wa (CPU waiting on I/O).


Verify your work

# Start a background sleep, confirm it's running, then signal it
sleep 600 &
jobs
pgrep -a sleep

# Terminate it gracefully and confirm it's gone
kill %1
pgrep sleep || echo "no sleep processes — terminated cleanly"

# Confirm PID 1 is systemd
ps -p 1 -o pid,comm

You should see the sleep job appear in jobs/pgrep, then disappear after kill, and PID 1 reported as systemd.

Summary

  • Every process has a PID and PPID; PID 1 is systemd, the root of the process tree.
  • View processes with ps aux / ps -ef, the tree with pstree, and live activity with top / htop; find PIDs with pgrep / pidof.
  • kill/killall/pkill send signals; prefer SIGTERM (graceful) over SIGKILL (-9, uncatchable); SIGHUP often triggers a config reload.
  • Niceness (-20 to +19) sets scheduling priority via nice/renice; only root can raise priority (negative values).
  • Job control (&, jobs, fg, bg, Ctrl-Z) manages foreground/background work; nohup/disown survive logout, but systemd/tmux are more robust.
  • /proc/<PID>/ exposes per-process kernel state; uptime, free -h, and vmstat give quick system-load snapshots.

Test yourself