Linux Process Management
A comprehensive guide to Linux process management: ps, top, kill, signals, systemd services, cgroups, resource limits, and the tools you need to keep systems running.
What you'll learn
- ✓How to inspect running processes with ps, top, and htop
- ✓Signals and the right way to stop processes
- ✓Managing services with systemd
- ✓Resource limits with cgroups and ulimit
- ✓Debugging runaway processes and memory leaks
Prerequisites
- •Basic Linux command line usage
- •Understanding of what a process is
- •SSH access to a Linux system (for hands-on practice)
Every running program on a Linux system is a process. Understanding how to inspect, control, and manage processes is fundamental to operating any Linux server. Whether you are debugging a stuck deployment, investigating high CPU usage, or configuring a service to restart on failure, process management is the skill you reach for.
Process fundamentals
Every process has a PID (process ID), a parent PID (PPID), an owner (UID), a state, and resource usage metrics. The kernel tracks all of this.
# See your shell's PID
echo $$
# 1234
# See the parent PID
echo $PPID
# 1230
Process states
| State | Code | Description |
|---|---|---|
| Running | R | Actively using CPU or ready to run |
| Sleeping | S | Waiting for an event (I/O, timer) |
| Uninterruptible Sleep | D | Waiting for I/O (cannot be killed) |
| Stopped | T | Paused by a signal (SIGSTOP, Ctrl+Z) |
| Zombie | Z | Finished but parent has not collected exit status |
Viewing processes with ps
ps shows a snapshot of current processes.
# Your processes
ps
# PID TTY TIME CMD
# 1234 pts/0 00:00:00 bash
# 5678 pts/0 00:00:00 ps
# All processes, full format
ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 1 0.0 0.1 169456 11832 ? Ss Jun29 0:03 /sbin/init
# postgres 42 0.1 2.3 398756 92344 ? Ss Jun29 1:42 postgres
# All processes, tree format
ps auxf
# Filter by name
ps aux | grep nginx
# root 1201 0.0 0.1 65432 5432 ? Ss Jun29 0:00 nginx: master
# www-data 1202 0.3 0.5 67890 21234 ? S Jun29 2:15 nginx: worker
# Show specific columns
ps -eo pid,ppid,user,%cpu,%mem,stat,start,command --sort=-%cpu | head -20
Finding processes
# Find by name
pgrep -la nginx
# 1201 nginx: master process
# 1202 nginx: worker process
# Find by port
ss -tlnp | grep :8080
# Or with lsof
lsof -i :8080
# Find by user
ps -u postgres
# Process tree for a specific PID
pstree -p 1201
Interactive monitoring with top and htop
top provides a live view of system resource usage.
top
Key information in top:
top - 14:32:01 up 45 days, load average: 1.23, 0.98, 0.87
Tasks: 234 total, 2 running, 232 sleeping, 0 stopped, 0 zombie
%Cpu(s): 5.2 us, 1.3 sy, 0.0 ni, 93.2 id, 0.3 wa, 0.0 hi, 0.0 si
MiB Mem: 16384.0 total, 2048.0 free, 10240.0 used, 4096.0 buff/cache
MiB Swap: 4096.0 total, 4000.0 free, 96.0 used. 5632.0 avail Mem
Key fields:
- load average: 1-min, 5-min, 15-min average number of processes in the run queue. Compare to CPU count.
- us: user-space CPU (your apps)
- sy: kernel CPU (system calls)
- wa: I/O wait (process waiting for disk)
- id: idle
Useful top shortcuts:
P- sort by CPUM- sort by memoryk- kill a process (enter PID)1- show per-CPU statsc- show full command lineq- quit
htop is a better version of top with colors, mouse support, and tree view.
# Install if not present
sudo apt install htop # Debian/Ubuntu
sudo yum install htop # RHEL/CentOS
htop
Signals
Signals are the mechanism for communicating with processes. kill sends signals (despite the name, it does not always kill).
# Common signals
kill -l # List all signals
# SIGTERM (15) - polite shutdown request (default)
kill 1234
kill -15 1234
kill -SIGTERM 1234
# SIGKILL (9) - force kill (cannot be caught)
kill -9 1234
kill -SIGKILL 1234
# SIGHUP (1) - reload configuration
kill -1 1234
kill -SIGHUP 1234
# SIGSTOP (19) - pause process
kill -STOP 1234
# SIGCONT (18) - resume paused process
kill -CONT 1234
# SIGUSR1/SIGUSR2 - user-defined (apps use for custom actions)
kill -USR1 1234
Signal handling best practices
Always try SIGTERM first. Give the process time to clean up. Only use SIGKILL as a last resort.
# Graceful shutdown pattern
kill $PID
sleep 5
# Check if still running
if kill -0 $PID 2>/dev/null; then
echo "Process did not stop gracefully, force killing"
kill -9 $PID
fi
Kill by name
# Kill all processes matching a name
pkill nginx
# Kill with signal
pkill -HUP nginx
# Kill all processes by a user
pkill -u baduser
# Kill processes matching a pattern
pkill -f "python manage.py runserver"
Foreground and background jobs
# Run in background
./long-task.sh &
# [1] 12345
# List background jobs
jobs
# [1]+ Running ./long-task.sh &
# Bring to foreground
fg %1
# Suspend current foreground process
# Press Ctrl+Z
# [1]+ Stopped ./long-task.sh
# Resume in background
bg %1
# Disown a job (keeps running after logout)
disown %1
nohup for persistent processes
# Run immune to hangups
nohup ./server.sh &
# Output goes to nohup.out by default
# With custom log file
nohup ./server.sh > /var/log/server.log 2>&1 &
echo "Server PID: $!"
systemd service management
systemd is the init system on modern Linux distributions. It manages services (daemons) as units.
# Start/stop/restart
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
# Reload config without full restart
sudo systemctl reload nginx
# Enable at boot / disable
sudo systemctl enable nginx
sudo systemctl disable nginx
# Check status
systemctl status nginx
# nginx.service - A high performance web server
# Loaded: loaded (/etc/systemd/system/nginx.service; enabled)
# Active: active (running) since Mon 2026-06-29 10:00:00 UTC; 1 day ago
# Main PID: 1201 (nginx)
# Tasks: 5 (limit: 4915)
# Memory: 12.3M
# CPU: 1min 42s
# View logs
journalctl -u nginx
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -f # Follow (tail)
Writing a systemd service file
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/venv/bin/python -m uvicorn main:app --host 0.0.0.0 --port 8000
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/myapp/data /var/log/myapp
# Resource limits
MemoryMax=512M
CPUQuota=200%
# Environment
Environment=NODE_ENV=production
EnvironmentFile=/opt/myapp/.env
[Install]
WantedBy=multi-user.target
# After creating or modifying a service file
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp
Restart policies
| Restart= value | Behavior |
|---|---|
no | Never restart |
on-failure | Restart on non-zero exit |
on-abnormal | Restart on signal, timeout, or watchdog |
on-abort | Restart on signal only |
always | Always restart (even on clean exit) |
Resource limits with ulimit
ulimit sets per-user resource limits for the current shell session.
# View all limits
ulimit -a
# Max open files (commonly needs increase for web servers)
ulimit -n
# 1024 (default)
ulimit -n 65536
# Set to 65536 for this session
# Max processes
ulimit -u
# Max file size
ulimit -f
# Core dump size (0 = disabled)
ulimit -c
For permanent limits, edit /etc/security/limits.conf:
# /etc/security/limits.conf
appuser soft nofile 65536
appuser hard nofile 65536
appuser soft nproc 4096
appuser hard nproc 4096
cgroups: resource control
cgroups (control groups) limit and isolate resource usage for groups of processes. systemd uses cgroups under the hood.
# View cgroup hierarchy
systemd-cgls
# Resource usage by cgroup
systemd-cgtop
# View a service's cgroup limits
systemctl show myapp.service | grep -i memory
systemctl show myapp.service | grep -i cpu
Setting cgroup limits via systemd
# In your service file's [Service] section
# Memory limits
MemoryMax=1G # Hard limit
MemoryHigh=768M # Throttle point
# CPU limits
CPUQuota=150% # 1.5 CPUs worth
CPUWeight=100 # Relative weight (default 100)
# I/O limits
IOWeight=100 # Relative I/O weight
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 50M
# Process limits
TasksMax=512 # Max number of tasks/threads
# Apply changes
sudo systemctl daemon-reload
sudo systemctl restart myapp
# Verify
systemctl show myapp.service -p MemoryMax
Debugging runaway processes
High CPU
# Find the culprit
top -bn1 | head -20
# Get thread-level detail
top -H -p $PID
# See what the process is doing (system calls)
strace -p $PID -c
# Press Ctrl+C after a few seconds to see summary
# CPU profiling (if perf is installed)
sudo perf top -p $PID
High memory
# Sort by memory usage
ps aux --sort=-%mem | head -10
# Detailed memory map of a process
pmap -x $PID
# Check for memory leaks over time
while true; do
ps -p $PID -o rss= >> /tmp/mem_$PID.log
sleep 60
done
Too many open files
# Count open files for a process
ls /proc/$PID/fd | wc -l
# See what files are open
lsof -p $PID | head -30
# System-wide open file count
cat /proc/sys/fs/file-nr
# 3456 0 65536 (allocated, free, max)
Zombie processes
# Find zombies
ps aux | awk '$8 ~ /Z/ {print}'
# Find the parent of a zombie
ps -o ppid= -p $ZOMBIE_PID
# The parent needs to call wait(). Sending SIGCHLD to the parent sometimes helps
kill -SIGCHLD $PARENT_PID
# If the parent is stuck, killing the parent clears the zombies
# (init/systemd adopts and reaps them)
Useful process management commands
# Run with lower priority
nice -n 10 ./cpu-intensive-task.sh
# Change priority of running process
renice -n 5 -p $PID
# Run in background, get PID
./server.sh &
echo "Server PID: $!"
# Wait for background process
./task.sh &
task_pid=$!
wait $task_pid
echo "Task exited with code: $?"
# Timeout a command
timeout 30s curl http://slow-api.example.com
# Watch a command repeatedly
watch -n 2 'ps aux --sort=-%cpu | head -10'
# Track process creation in real time
sudo execsnoop-bpfcc # requires bcc-tools
Process management is the foundation of Linux system administration. Know how to find what is running, understand what it is doing, control its resources, and stop it cleanly. These tools and patterns apply whether you are managing a single server or a fleet of thousands.
Related articles
- Linux Linux Process Management Explained: ps, top, kill, and Beyond
Learn how Linux processes work, how to inspect them with ps and top, and how to control them with signals so your servers stay responsive.
- Linux Linux Cron Jobs and systemd Timers
Master scheduled tasks on Linux. Learn crontab syntax, fix common PATH and environment pitfalls, and use systemd timers as a modern alternative.
- Linux Linux Networking Commands: ip, ss, curl, dig
A practical guide to modern Linux networking tools. Learn ip, ss, curl, and dig to diagnose connectivity, inspect sockets, and resolve DNS issues fast.
- Linux Linux awk and sed: Text Processing Power Tools
Master awk and sed for text processing on Linux. Learn pattern matching, field extraction, in-place editing, and real-world one-liners for log analysis.