Linux Process Management: ps, top, kill, and nice

Every program running on a Linux system is a process. When you open a text editor, start a web server, or run a backup script, the kernel creates a process with a unique identifier (PID) and...

Key Insights

  • The ps command provides snapshots of processes, while top offers real-time monitoring—use ps aux --sort=-%cpu for quick CPU hog identification and top for interactive troubleshooting
  • Always send SIGTERM (kill -15) before SIGKILL (kill -9) to allow processes to clean up resources gracefully—force-killing can leave orphaned connections and corrupted data
  • Nice values range from -20 (highest priority) to 19 (lowest priority), but lowering nice values requires root access—use this for batch jobs that shouldn’t compete with critical services

Understanding Linux Processes

Every program running on a Linux system is a process. When you open a text editor, start a web server, or run a backup script, the kernel creates a process with a unique identifier (PID) and allocates system resources to it. Understanding how to view, monitor, and control these processes is fundamental to system administration and troubleshooting.

Processes exist in different states: running (actively using CPU), sleeping (waiting for an event or resource), stopped (suspended by a signal), and zombie (completed but waiting for parent to read exit status). Zombie processes are particularly interesting—they consume minimal resources but indicate the parent process isn’t properly handling child termination.

Let’s examine a basic process listing:

ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 169564 13452 ?        Ss   Jan15   0:42 /sbin/init
www-data  1234  2.3  1.5 523456 62344 ?        S    10:23   1:15 nginx: worker
mysql     5678  8.1  4.2 2847392 172584 ?      Sl   Jan15  45:32 /usr/sbin/mysqld
john      9012  0.0  0.1  21532  5124 pts/0    R+   14:32   0:00 ps aux

The STAT column reveals process states: S for sleeping, R for running, Z for zombie. Additional characters indicate modifiers: s for session leader, l for multi-threaded, + for foreground process group.

Viewing Processes with ps

The ps command is your primary tool for process inspection. While it has dozens of options, mastering a few key patterns covers most use cases.

The aux options show all processes with user-oriented formatting:

ps aux | grep nginx
www-data  1234  0.5  1.5 523456 62344 ?  S  10:23  1:15 nginx: master process
www-data  1235  0.3  0.8 523888 34212 ?  S  10:23  0:52 nginx: worker process

For hierarchical views showing parent-child relationships, use the --forest option:

ps -ef --forest
UID        PID  PPID  C STIME TTY      TIME CMD
root         1     0  0 Jan15 ?        00:00:42 /sbin/init
root       823     1  0 Jan15 ?        00:00:12  \_ /usr/sbin/sshd -D
root      8234   823  0 14:20 ?        00:00:00      \_ sshd: john [priv]
john      8256  8234  0 14:20 ?        00:00:00          \_ sshd: john@pts/0
john      8257  8256  0 14:20 pts/0    00:00:00              \_ -bash

Custom output formatting gives you exactly the information you need:

ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -10
  PID  PPID CMD                         %MEM %CPU
 5678     1 /usr/sbin/mysqld             4.2  8.1
 3421     1 /usr/bin/python3 app.py      2.8  5.3
 1234     1 nginx: master process        1.5  2.3

This one-liner sorts by CPU usage and displays the top 10 processes—invaluable when investigating performance issues.

Real-Time Monitoring with top

While ps provides snapshots, top offers dynamic, real-time process monitoring. The interface updates every few seconds, showing system-wide statistics and per-process metrics.

top
top - 14:35:42 up 12 days,  4:12,  3 users,  load average: 1.23, 1.45, 1.67
Tasks: 247 total,   2 running, 245 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.5 us,  3.2 sy,  0.0 ni, 83.1 id,  1.2 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  15923.4 total,   2134.2 free,   8456.1 used,   5333.1 buff/cache
MiB Swap:   4096.0 total,   3892.0 free,    204.0 used.   6234.8 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 5678 mysql     20   0 2847392 172584  23456 S   8.1   4.2  45:32.18 mysqld
 3421 www-data  20   0  456123 114232  12345 R   5.3   2.8  12:45.67 python3

The load average shows 1, 5, and 15-minute averages. On a 4-core system, values under 4.0 generally indicate healthy load. The CPU line breaks down time spent in user space (us), system/kernel (sy), nice processes (ni), idle (id), and I/O wait (wa).

Interactive commands make top powerful:

  • Press M to sort by memory usage
  • Press P to sort by CPU usage
  • Press k to kill a process
  • Press r to renice a process
  • Press u then enter username to filter by user

Filter processes for a specific user:

top -u nginx

For batch mode output suitable for logging:

top -b -n 1 | head -20 > system_snapshot.txt

Consider htop as a more user-friendly alternative with color coding, mouse support, and easier process tree navigation. Install it with your package manager and run htop for an enhanced experience.

Controlling Processes with kill

The kill command doesn’t just terminate processes—it sends signals that processes can handle in different ways. Understanding signals is crucial for graceful process management.

Common signals:

  • SIGTERM (15): Polite request to terminate, allows cleanup
  • SIGKILL (9): Immediate termination, cannot be caught or ignored
  • SIGHUP (1): Hangup signal, often used to reload configuration
  • SIGSTOP (19): Pause process execution
  • SIGCONT (18): Resume paused process

Always try SIGTERM before SIGKILL:

kill -15 1234
# Wait a few seconds
kill -9 1234  # Only if process didn't terminate

Or use the default (SIGTERM) and escalate:

kill 1234
sleep 5
kill -9 1234

The killall command terminates all processes matching a name:

killall nginx

The pkill command offers pattern matching:

pkill -f "python.*backup.py"

This kills all Python processes with “backup.py” in their command line. The -f flag matches against the full command line, not just the process name.

For more precision, combine with user filtering:

pkill -u www-data -f "php-fpm"

Process Priority with nice and renice

Linux uses nice values to determine CPU scheduling priority. The name comes from the idea that a process with a higher nice value is “nicer” to other processes by demanding less CPU time.

Nice values range from -20 (highest priority) to 19 (lowest priority). Default is 0. Only root can set negative values or lower existing nice values.

Start a process with lower priority:

nice -n 10 ./backup-database.sh

This ensures your backup script doesn’t interfere with production workloads. For CPU-intensive batch jobs, consider even higher values:

nice -n 19 ./video-encoding-job.sh

Adjust a running process with renice:

renice -n 5 -p 1234

Renice all processes owned by a user:

renice -n 10 -u batchuser

View current nice values:

ps -eo pid,ni,cmd | grep myapp
 1234  10 /usr/bin/myapp --config prod.conf
 1235   0 /usr/bin/myapp --worker

In practice, nice values make the most difference on CPU-bound workloads. I/O-bound processes spend most of their time waiting anyway, so adjusting priority has minimal impact.

Practical Scenarios and Best Practices

Finding Memory Hogs

When your system is running low on memory:

ps aux --sort=-%mem | head -10

Or for a quick one-liner showing the top 5:

ps aux | awk '{print $2, $4, $11}' | sort -k2 -nr | head -6

Automated Process Monitoring

Create a simple watchdog script:

#!/bin/bash
if ! pgrep -f "myapp" > /dev/null; then
    echo "$(date): myapp not running, restarting..." >> /var/log/watchdog.log
    /usr/local/bin/myapp &
fi

Add to cron for periodic checks:

*/5 * * * * /usr/local/bin/watchdog.sh

Investigating High CPU Usage

Combine top with logging for historical analysis:

while true; do
    top -b -n 1 | head -20 >> /var/log/top_snapshots.log
    echo "---" >> /var/log/top_snapshots.log
    sleep 300
done

Graceful Service Restarts

For services that support configuration reload:

pkill -HUP nginx  # Reload nginx configuration

This is far superior to kill/restart cycles that drop connections.

Quick Reference and Next Steps

Task Command
List all processes ps aux
Find specific process ps aux | grep name
Process tree ps -ef --forest
Real-time monitoring top or htop
Kill gracefully kill -15 PID
Force kill kill -9 PID
Kill by name pkill name
Start with low priority nice -n 10 command
Change priority renice -n 5 -p PID

These four commands form the foundation of process management, but modern Linux offers additional tools. Explore systemd for service management, cgroups for resource limiting, and /proc filesystem for deep process inspection. Tools like pstree, pgrep, and pidof complement the core commands covered here.

Master these fundamentals first. When you can quickly identify resource-hungry processes, gracefully terminate misbehaving services, and adjust priorities to prevent system overload, you’ll handle most operational challenges with confidence.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.