Linux Process Management: Signals, Priorities, and Service Control
Every running program on a Linux system is a process. Understanding how to inspect, control, prioritize, and terminate processes is a core system administration skill. This guide covers the essential tools and techniques for process management, from basic inspection commands to service orchestration with systemctl.
Part of the Linux System Administration guide. See also: Systemd Guide | Performance Monitoring
Inspecting Processes
ps: Process Snapshots
The ps command provides a snapshot of currently running processes. The most common invocation is ps aux, which shows all processes with detailed information:
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 169436 13092 ? Ss Mar10 0:15 /sbin/init
root 2 0.0 0.0 0 0 ? S Mar10 0:00 [kthreadd]
www-data 1542 0.2 1.5 456320 125440 ? Sl 09:00 1:22 /usr/sbin/apache2
postgres 1987 0.1 2.3 398712 189248 ? Ss 09:01 0:45 postgres: writer
Key columns: PID (process ID), %CPU and %MEM (resource usage), STAT (process state), COMMAND (the executable and arguments).
Process states in STAT: S sleeping, R running, D uninterruptible sleep (usually I/O), Z zombie, T stopped. Additional characters: s session leader, l multi-threaded, + foreground process group.
Useful ps variations:
# Show process tree (parent-child relationships)
ps auxf
# Show processes for a specific user
ps -u postgres
# Show specific columns
ps -eo pid,ppid,user,%cpu,%mem,cmd --sort=-%cpu | head -20
# Find processes by name
ps aux | grep nginx
# Or more precisely:
pgrep -a nginx
top and htop: Real-Time Monitoring
top provides a continuously updating view of system processes sorted by CPU usage:
$ top
# Key commands inside top:
# M - sort by memory usage
# P - sort by CPU usage
# k - kill a process (enter PID)
# r - renice a process
# 1 - show individual CPU cores
# q - quit
htop is an enhanced, more user-friendly alternative. It provides color-coded output, mouse support, tree view, and easier process management. Install it with your package manager (apt install htop or dnf install htop):
$ htop
# Key commands inside htop:
# F5 - tree view
# F6 - choose sort column
# F9 - kill menu (select signal)
# F2 - setup/configuration
# / - search for process
# u - filter by user
Signals: Communicating with Processes
Signals are the primary mechanism for communicating with running processes. The kill command sends signals despite its name; termination is just one possibility.
Common Signals
| Signal | Number | Default Action | Purpose |
|---|---|---|---|
| SIGHUP | 1 | Terminate | Hangup; many daemons reload config on SIGHUP |
| SIGINT | 2 | Terminate | Interrupt (same as Ctrl+C) |
| SIGQUIT | 3 | Core dump | Quit with core dump |
| SIGKILL | 9 | Terminate | Force kill; cannot be caught or ignored |
| SIGTERM | 15 | Terminate | Graceful termination (default signal) |
| SIGSTOP | 19 | Stop | Pause process; cannot be caught |
| SIGCONT | 18 | Continue | Resume a stopped process |
Sending Signals
# Send SIGTERM (default, graceful shutdown)
kill 1542
kill -15 1542
kill -SIGTERM 1542
# Send SIGHUP (reload configuration)
kill -1 1542
kill -SIGHUP 1542
# Force kill (last resort; process cannot clean up)
kill -9 1542
kill -SIGKILL 1542
# Kill all processes by name
killall nginx
pkill -f "python app.py"
# Send signal to all processes of a user
pkill -u baduser
Best practice: Always try SIGTERM first. Give the process a few seconds to shut down gracefully. Only use SIGKILL if SIGTERM fails, because SIGKILL prevents cleanup (temporary files, lock files, database connections may be left in a dirty state).
Handling Zombie Processes
A zombie process (Z state) is a child process that has finished but whose parent has not yet read its exit status. Zombies consume a PID but no other resources. You cannot kill a zombie directly; you must either signal the parent to reap it or kill the parent:
# Find zombies
ps aux | awk '$8 ~ /Z/'
# Find the parent of a zombie
ps -o ppid= -p <zombie_pid>
Process Priority: nice and renice
Linux uses a priority system from -20 (highest priority) to 19 (lowest priority). The default nice value is 0. Only root can set negative nice values.
# Start a process with low priority
nice -n 10 tar czf backup.tar.gz /data
# Start with high priority (root only)
nice -n -5 /opt/critical-app/run.sh
# Change priority of a running process
renice 15 -p 1542
# Renice all processes of a user
renice 10 -u developer
Low-priority tasks like backups and batch jobs should be niced to avoid impacting interactive or customer-facing workloads.
Job Control: bg, fg, and jobs
The shell provides built-in job control for managing multiple processes within a terminal session.
# Start a process in the background
./long_running_task.sh &
# Suspend the current foreground process
# Press Ctrl+Z
# List background and stopped jobs
$ jobs
[1]+ Stopped vim config.yaml
[2]- Running ./compile.sh &
# Resume job 1 in the foreground
fg %1
# Resume job 1 in the background
bg %1
# Bring the most recent background job to the foreground
fg
nohup: Surviving Logout
When you log out, your shell sends SIGHUP to all its child processes, which typically terminates them. nohup makes a process immune to SIGHUP:
# Run a process that survives logout
nohup ./data_migration.sh &
# Output goes to nohup.out by default; redirect if preferred
nohup ./data_migration.sh > /var/log/migration.log 2>&1 &
# Alternatively, use disown to detach an already-running job
./long_task.sh &
disown %1
For long-running tasks on remote servers, consider using screen or tmux instead of nohup for better session management.
Managing Services with systemctl
On modern Linux distributions using systemd, services are managed with systemctl. This is the primary interface for starting, stopping, enabling, and inspecting system services.
# Start, stop, and restart a service
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
# Reload configuration without full restart (if supported)
systemctl reload nginx
# Enable a service to start at boot
systemctl enable nginx
# Disable a service from starting at boot
systemctl disable nginx
# Check service status
systemctl status nginx
# View all running services
systemctl list-units --type=service --state=running
# View all failed services
systemctl --failed
# Show service dependencies
systemctl list-dependencies nginx
Inspecting Service Logs
Systemd integrates with journalctl for centralized logging:
# View logs for a specific service
journalctl -u nginx
# Follow logs in real time
journalctl -u nginx -f
# Show logs since last boot
journalctl -u nginx -b
# Show logs from the last hour
journalctl -u nginx --since "1 hour ago"
Practical Tips
- Use
pgrepandpkillinstead ofps | greppipelines for reliability - Monitor for zombie processes in your alerting system; a growing count indicates a buggy parent process
- Set appropriate nice values for batch jobs and backups
- Use
systemctlrather than direct process management for services; it handles dependencies, logging, restart policies, and resource limits - When a process is stuck in
Dstate (uninterruptible sleep), it is usually waiting on I/O; investigate the storage subsystem rather than trying to kill the process