The Problem
An application is consuming 100% CPU. A zombie process is holding a port. You need to find which process owns a file, send it a graceful shutdown signal, and verify it terminated. Process management is the foundation of Linux troubleshooting.
ps — View Running Processes
ps aux # All processes, full detail
ps auxf # Tree format (parent-child)
ps -u deploy # Specific user
pgrep -a nginx # Find by name
ps -eo pid,ppid,user,%cpu,%mem,stat,start,time,command --sort=-%mem | head -20
ps -eo pid,nlwp,command --sort=-nlwp | head -20 # Thread count
Reading ps output
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
www-data 1234 45.2 8.3 2345678 678900 ? Sl 10:23 12:34 java -jar app.jar
deploy 5678 0.0 0.0 0 0 ? Z Jan12 0:00 [defunct]
- RSS — Actual physical memory used (use this for capacity planning)
- VSZ — Virtual memory (includes unmapped space)
- STAT — Process state
Process states
| State | Meaning |
|---|---|
| <code class="inline-code">R</code> | Running or runnable |
| <code class="inline-code">S</code> | Sleeping (waiting) |
| <code class="inline-code">D</code> | Uninterruptible sleep (I/O) |
| <code class="inline-code">Z</code> | Zombie (terminated, not reaped) |
| <code class="inline-code">T</code> | Stopped |
| <code class="inline-code">s</code> | Session leader |
| <code class="inline-code">l</code> | Multi-threaded |
top and htop
top # Real-time view
top -o %MEM # Sort by memory
top -u deploy # Specific user
top -bn1 | head -20 # Batch mode for scripts
htop --tree # Interactive with tree view
top keyboard shortcuts
| Key | Action |
|---|---|
| <code class="inline-code">M</code> | Sort by memory |
| <code class="inline-code">P</code> | Sort by CPU |
| <code class="inline-code">k</code> | Kill a process |
| <code class="inline-code">c</code> | Toggle full command |
| <code class="inline-code">H</code> | Show threads |
| <code class="inline-code">1</code> | Per-CPU usage |
| <code class="inline-code">q</code> | Quit |
Finding Processes
By name
pgrep -a nginx
pgrep -l nginx
pgrep -c nginx
pidof nginx
By port
ss -tlnp | grep 8080
lsof -i :8080
fuser 8080/tcp
By file
lsof /var/log/app/application.log
lsof +D /var/log/app/
lsof +L1 | grep deleted # Invisible disk space usage
By resource usage
ps aux --sort=-%cpu | head -11
ps aux --sort=-%mem | head -11
ps aux | awk '$6 > 1048576 {print $0}' # RSS > 1GB
Sending Signals
Common signals
| Signal | Number | Behavior |
|---|---|---|
| <code class="inline-code">SIGHUP</code> | 1 | Reload config |
| <code class="inline-code">SIGINT</code> | 2 | Interrupt (Ctrl+C) |
| <code class="inline-code">SIGTERM</code> | 15 | Graceful termination |
| <code class="inline-code">SIGKILL</code> | 9 | Force kill (uncatchable) |
| <code class="inline-code">SIGUSR1</code> | 10 | User-defined |
| <code class="inline-code">SIGSTOP</code> | 19 | Pause process |
| <code class="inline-code">SIGCONT</code> | 18 | Resume process |
Usage
kill 1234 # SIGTERM (graceful)
kill -9 1234 # SIGKILL (force)
kill -HUP 1234 # Reload config
pkill nginx # Kill by name
pkill -9 nginx # Force kill by name
pkill -u baduser # Kill all user processes
kill -TERM -1234 # Kill process group
Graceful shutdown pattern
kill $PID
sleep 5
if kill -0 $PID 2>/dev/null; then
echo "Still running, force killing"
kill -9 $PID
fi
Background Jobs
# Run in background
long-running-command &
# Disown (survives shell exit)
long-running-command &
disown
# Immune to hangups
nohup long-running-command > output.log 2>&1 &
# tmux (best for interactive)
tmux new -s deploy
# ... run commands ...
# Ctrl+B, D to detach
tmux attach -t deploy
Job control
jobs # List background jobs
fg %1 # Bring to foreground
# Ctrl+Z to pause, then:
bg %1 # Send to background
wait $PID # Wait for completion
Zombie Processes
# Find zombies
ps aux | awk '$8 ~ /Z/ {print}'
# Find parent of zombies
ps -eo pid,ppid,stat,command | grep "Z"
# Fix: kill or restart the parent process
# Zombies themselves cannot be killed
Process Priority
nice -n 10 heavy-task.sh # Start with lower priority
nice -n -20 critical-task.sh # Highest priority (root)
renice 10 -p 1234 # Change running process
renice -5 -p 1234 # Higher priority (root)
Nice values: -20 (highest priority) to 19 (lowest). Default is 0.
Troubleshooting Patterns
CPU hog
top -bn1 -o %CPU | head -15
ps -T -p 1234 -o spid,pcpu,time,command | sort -k2 -rn | head -20
pidstat -p 1234 2
Memory hog
ps aux --sort=-rss | head -20
pmap -x 1234
Disk I/O
iotop -o
pidstat -d -p 1234 2
Common Mistakes
kill -9 first — SIGKILL skips cleanup (temp files, locks, connections). Always try SIGTERM first.ps aux | grep nginx matches grep. Use pgrep -a nginx instead.pkill java kills ALL Java processes. Use pkill -f "java.*specific-app".Quick Reference
| Task | Command | |
|---|---|---|
| All processes | <code class="inline-code">ps aux</code> | |
| Process tree | <code class="inline-code">ps auxf</code> | |
| Find by name | <code class="inline-code">pgrep -a name</code> | |
| Find by port | <code class="inline-code">ss -tlnp \ | grep PORT</code> |
| Top CPU users | <code class="inline-code">ps aux --sort=-%cpu \ | head</code> |
| Top memory users | <code class="inline-code">ps aux --sort=-%mem \ | head</code> |
| Graceful kill | <code class="inline-code">kill PID</code> | |
| Force kill | <code class="inline-code">kill -9 PID</code> | |
| Reload config | <code class="inline-code">kill -HUP PID</code> | |
| Background job | <code class="inline-code">command &</code> | |
| Survive SSH | <code class="inline-code">nohup command &</code> or <code class="inline-code">tmux</code> | |
| Find zombies | <code class="inline-code">ps aux \ | awk '$8~/Z/'</code> |
| Process I/O | <code class="inline-code">iotop -o</code> | |
| Change priority | <code class="inline-code">renice 10 -p PID</code> |
Summary
Process management starts with identification (ps, pgrep, lsof), monitoring (top, htop), and control (kill, nice, jobs). Always SIGTERM before SIGKILL. Use tmux or systemd for persistent processes. Start troubleshooting with ps aux --sort=-%cpu or --sort=-%mem to find the resource hog immediately.
---
Frequently Asked Questions
How do I find and kill a process in Linux?
Use ps aux | grep <process-name> or pgrep <name> to find the process ID. Then use kill <pid> for graceful termination (SIGTERM) or kill -9 <pid> for forced termination (SIGKILL). For killing by name, use pkill <name> or killall <name>. Always try SIGTERM first to allow the process to clean up before using SIGKILL.
What is the difference between SIGTERM and SIGKILL?
SIGTERM (signal 15) asks the process to terminate gracefully — it can be caught, handled, and ignored by the process, allowing cleanup of resources. SIGKILL (signal 9) immediately terminates the process at the kernel level — it cannot be caught or ignored. Always use SIGTERM first and only escalate to SIGKILL if the process doesn't respond within a reasonable timeout.
How do I run a process in the background on Linux?
Append & to run a command in the background: ./script.sh &. Use nohup ./script.sh & to keep it running after logout. For better management, use screen or tmux sessions, or create a systemd service for production processes. Use jobs to list background processes and fg %1 to bring one to the foreground.
How do I check what resources a process is using?
Use top -p <pid> for real-time CPU and memory monitoring of a specific process. For more detail, check /proc/<pid>/status for memory breakdown, strace -p <pid> for system call activity, and lsof -p <pid> for open files and network connections. Use pidstat -p <pid> 1 for periodic per-process CPU, memory, and I/O statistics.
What is a zombie process and how do I fix it?
A zombie process has finished execution but its parent hasn't collected its exit status with wait(). It appears as <defunct> in ps output and consumes a process table entry but no resources. Fix by sending SIGCHLD to the parent process (kill -SIGCHLD <parent-pid>) or killing the parent, which makes init adopt and reap the zombie.
---
Related Resources
- Linux Commands Reference — 50+ Linux commands with production examples
- DevOps Interview Academy — Linux interview questions
- Linux Performance Troubleshooting — Diagnosing performance bottlenecks
- systemctl Service Management — Managing services via systemd
- Monitoring and Alerting in Production — Monitoring process health in production