What is a Process?#
Every running program on a Linux system is a process. When you type a command, the shell creates a new process to execute it. Each process has:
- PID — a unique process ID
- PPID — the parent process ID (the process that started it)
- Owner — the user who launched it
- State — running, sleeping, stopped, or zombie
# Every process traces back to PID 1 (systemd/init)
ps -ef | head -5Viewing Processes#
ps — Snapshot of Processes#
# Your processes in the current terminal
ps
# All processes on the system (full format)
ps -ef
# All processes (BSD style, with resource usage)
ps aux
# Filter by name
ps aux | grep nginx
# Show process tree
ps -ef --forestReading ps aux output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
mike 1234 0.5 1.2 123456 12345 pts/0 S 10:30 0:02 vim file.txt| Column | Meaning |
|---|---|
USER | Owner |
PID | Process ID |
%CPU | CPU usage percentage |
%MEM | Memory usage percentage |
VSZ | Virtual memory size (KB) |
RSS | Resident memory (actually in RAM, KB) |
TTY | Terminal associated with the process |
STAT | Process state |
START | Start time |
TIME | Total CPU time consumed |
COMMAND | Command that started the process |
Process states#
| State | Meaning |
|---|---|
R | Running |
S | Sleeping (waiting for input/event) |
D | Uninterruptible sleep (usually I/O) |
T | Stopped (suspended) |
Z | Zombie (finished but not cleaned up by parent) |
top — Real-Time Process Monitor#
topKey commands within top:
| Key | Action |
|---|---|
q | Quit |
k | Kill a process (prompts for PID) |
M | Sort by memory usage |
P | Sort by CPU usage |
1 | Show per-CPU usage |
u | Filter by user |
c | Toggle full command path |
htop — Better Interactive Monitor#
htophtop is a more user-friendly alternative to top with color, mouse support, and easier navigation. Install it with your package manager if it’s not available.
pgrep — Find Processes by Name#
# Get PID of nginx processes
pgrep nginx
# With full command shown
pgrep -a nginx
# By user
pgrep -u mikeSignals and Killing Processes#
Signals are how you communicate with processes. The most common:
| Signal | Number | Meaning |
|---|---|---|
SIGHUP | 1 | Hangup — often used to reload configuration |
SIGINT | 2 | Interrupt (same as Ctrl-c) |
SIGKILL | 9 | Force kill — cannot be caught or ignored |
SIGTERM | 15 | Graceful termination (default) |
SIGSTOP | 19 | Pause the process |
SIGCONT | 18 | Resume a paused process |
Sending signals#
# Graceful stop (default SIGTERM)
kill 1234
# Force kill
kill -9 1234
# Reload configuration
kill -HUP 1234
# Kill by name
killall nginx
# Kill by name (with signal)
pkill -HUP nginx
# Kill all processes by a user
pkill -u baduserWhen to use SIGKILL vs SIGTERM#
Always try SIGTERM (plain kill) first — it lets the process clean up (close files, finish writes, release locks). Only use kill -9 if the process doesn’t respond to SIGTERM, because SIGKILL gives the process no chance to clean up.
Job Control#
Jobs are processes started from your shell. You can suspend, resume, and move them between foreground and background.
Running in the background#
# Start a command in the background
long-running-command &
# Check background jobs
jobs
# Bring a background job to the foreground
fg %1
# Send the current foreground job to the background
# First: Ctrl-z (suspends it)
# Then:
bg %1Practical job control#
# Start a download in the background
wget https://example.com/bigfile.tar.gz &
# Suspend a running editor (Ctrl-z), do something else, then resume
vim file.txt
# Press Ctrl-z
fgnohup — Survive Logout#
Normally, background jobs die when you close the terminal. nohup prevents that:
nohup long-running-script.sh &Output goes to nohup.out. For more control, use tmux or screen.
Process Priority and niceness#
Every process has a nice value from -20 (highest priority) to 19 (lowest priority). Default is 0.
# Start a process with low priority
nice -n 10 heavy-computation
# Change priority of a running process
renice 10 -p 1234
# Only root can increase priority (lower nice value)
sudo renice -5 -p 1234Systemd and Services#
Most modern Linux distributions use systemd to manage services (background daemons). Services are defined in unit files and managed with systemctl.
Viewing service status#
# Check if a service is running
systemctl status nginx
# Is it active? (returns 0 or 1)
systemctl is-active nginx
# Is it enabled to start at boot?
systemctl is-enabled nginx
# List all running services
systemctl list-units --type=service --state=running
# List all services (including inactive)
systemctl list-units --type=service --allControlling services#
# Start a service
sudo systemctl start nginx
# Stop a service
sudo systemctl stop nginx
# Restart (stop + start)
sudo systemctl restart nginx
# Reload config without stopping
sudo systemctl reload nginx
# Enable at boot
sudo systemctl enable nginx
# Disable at boot
sudo systemctl disable nginx
# Enable and start in one command
sudo systemctl enable --now nginxViewing logs with journalctl#
Systemd captures output from all services in a structured journal:
# Logs for a specific service
journalctl -u nginx
# Follow logs in real time (like tail -f)
journalctl -u nginx -f
# Logs since last boot
journalctl -b
# Logs since a specific time
journalctl --since "1 hour ago"
journalctl --since "2026-06-09 10:00:00"
# Only errors and above
journalctl -u nginx -p err
# Kernel messages
journalctl -kUnit file basics#
Unit files live in /etc/systemd/system/ (custom) or /usr/lib/systemd/system/ (package-provided).
A simple service unit:
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=myapp
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target# After creating or modifying a unit file
sudo systemctl daemon-reload
# Then start it
sudo systemctl start myappCommon unit file options#
| Option | Meaning |
|---|---|
After= | Start after these units |
Type=simple | Process stays in foreground |
Type=forking | Process forks (traditional daemons) |
Restart=on-failure | Restart if it exits with an error |
Restart=always | Restart no matter what |
RestartSec=5 | Wait 5 seconds before restarting |
User= | Run as this user |
Environment= | Set environment variables |
WorkingDirectory= | Set working directory |
Resource Monitoring#
Memory usage#
# System memory overview
free -h
# Detailed per-process memory
ps aux --sort=-%mem | head -10CPU usage#
# Per-CPU stats
mpstat
# Top CPU consumers
ps aux --sort=-%cpu | head -10Disk I/O#
# Real-time I/O stats
iostat -x 1
# Per-process I/O
iotopCombined: top/htop shows CPU, memory, and process info in one view.#
The /proc Filesystem#
Every running process has a directory in /proc:
# Info about process 1234
ls /proc/1234/
# Command that started the process
cat /proc/1234/cmdline | tr '\0' ' '
# Environment variables
cat /proc/1234/environ | tr '\0' '\n'
# File descriptors (open files)
ls -l /proc/1234/fd/
# Memory maps
cat /proc/1234/mapsSystem-wide information:
cat /proc/cpuinfo # CPU details
cat /proc/meminfo # Memory details
cat /proc/uptime # System uptime
cat /proc/loadavg # Load averagesBest Practices#
- Use
SIGTERMbeforeSIGKILL— always give processes a chance to clean up - Use
systemctlto manage services, not manualkillcommands — systemd handles restarts and dependencies - Check
journalctl -u servicenamefirst when a service misbehaves — the answer is usually in the logs - Use
nicefor CPU-heavy batch jobs so they don’t starve interactive processes - Monitor zombie processes (
ps aux | grep Z) — they indicate a parent process isn’t handling child termination - Use
htopfor interactive investigation andps auxfor scriptable output - Enable
Restart=on-failurein unit files for services that should stay running - Avoid
nohupfor production workloads — write a proper systemd unit file instead

