| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | procps-ng 4.0.4-11.el10.x86_64psmisc 23.6-8.el10.x86_64 |
| Applies to | Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux |
| Privilege | Normal user for process listings and monitoring; sudo or root to signal processes owned by other users or access restricted process details |
| Scope | Integrated workflow to find, inspect, monitor, signal, and troubleshoot processes with ps, pgrep, top, and kill. Covers shell jobs versus system processes, parent-child trees, and zombie and D states at a practical level. Does not replace full ps, top, or kill command references. |
| Related guides | List processes in Linux ps command top command kill and pkill nice and renice |
Every running program on Linux becomes a process with a process ID (PID), an owner, a state, and a parent. Administrators spend most troubleshooting time tracing one misbehaving PID through listing tools, live monitors, signals, and service ownership — not memorizing every ps flag in isolation.
This guide walks that end-to-end workflow on a single host. For flag-level depth on individual tools, use the linked command references in each section.
What is a Linux process?
A program is a file on disk (/usr/bin/bash, a compiled binary, or a script). A process is that program while it is executing. The kernel tracks each process with:
- PID — unique numeric ID for this running instance
- PPID — parent PID; most user commands are children of your shell or of
systemd - User — UID that owns the process; determines what files and signals you can use against it
- Command — argv shown by
ps(may truncate long lines) - State — running, sleeping, stopped, zombie, and other codes in the
STATcolumn - Threads — one process can have multiple kernel-scheduled threads;
psandtopusually show the main thread or task count depending on options
Kernel threads and user daemons appear in the same tables as your shell commands. systemd (PID 1 on modern distros) is the root of most service trees.
List, find, and trace parent-child processes
Start with a snapshot of what is running. The ps command reads process data from /proc; see also list processes in Linux for user and name filters.
ps aux and ps -ef request a system-wide listing. Plain ps without those flags normally shows only processes tied to your user and terminal.
List every process with owner, CPU, memory, and state (BSD style):
ps auxUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 44580 17752 ? Ss Aug04 0:16 /usr/lib/systemd/systemd --switched-root --system --deserialize=43 rhgbSysV-style full format includes parent PID and start time:
ps -efUID PID PPID C STIME TTY TIME CMD
root 1 0 0 Aug04 ? 00:00:16 /usr/lib/systemd/systemd --switched-root --system --deserialize=43 rhgbpidof returns PIDs for a binary name when the executable path matches:
pidof bash41078 33715 32125Filter by user:
ps -u "$(whoami)" -o pid,stat,cmdReplace $(whoami) with a username to inspect another account when you have permission.
PPID links every process to its parent. A runaway worker may be harmless to kill; a parent systemd unit or wrapper script may respawn it seconds later.
Forest view for one process tree:
ps -ef --forest | head -20pstree shows the same hierarchy with PIDs attached:
pstree -p | head -15systemd(1)-+-ModemManager(1156)-+-{ModemManager}(1162)
|-NetworkManager(1080)-+-{NetworkManager}(1105)
|-accounts-daemon(1088)-+-{accounts-daemon}(1129)When a process is managed by systemd, stop the unit instead of only killing the worker PID:
systemctl status sshd● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-08-04 10:08:28 IST; 1 day 8h agoUse systemctl stop or systemctl restart on the unit name when the exam or runbook expects service-level control.
RHEL-family systems use sshd.service. Debian and Ubuntu commonly use ssh.service, so confirm the unit name before running systemctl stop or systemctl restart.
Process states, zombies, and uninterruptible sleep
The STAT column in ps encodes state plus optional modifiers. Common base states:
| Code | Meaning |
|---|---|
R |
Running or runnable — on the CPU or waiting for a CPU slot |
S |
Interruptible sleep — waiting for an event (timer, network, disk) |
D |
Uninterruptible sleep — blocked on I/O; SIGKILL may not end the task until the kernel I/O completes or fails |
T |
Stopped — job control or debugger |
Z |
Zombie — exited but parent has not collected exit status |
D means uninterruptible sleep, while SIGKILL does not give the process an opportunity to clean up. Modifiers such as s (session leader), l (multi-threaded), and + (foreground job) appear after the letter. A sleeping S process is normal for idle daemons; state alone does not prove a bug.
Inspect state for the current shell (PID $$ is always available):
ps -p $$ -o pid,ppid,user,stat,cmdPID PPID USER STAT CMD
41145 41131 root S bash --norcS or Ss is normal for an idle shell waiting for input. A CPU loop shows R while it runs.
A zombie (Z in STAT) is a terminated but unreaped process. It uses no CPU and no longer has its normal user-space address space, but it retains a PID and a small process-table entry until the parent collects its exit status with wait(). Killing the zombie PID does not work. Fix the parent — restart the service, fix the buggy parent, or reboot as a last resort.
Persistent D state usually means the process is stuck in kernel I/O. SIGKILL cannot be caught or ignored, but a process blocked in uninterruptible sleep may remain visible until the kernel I/O operation completes or fails. Persistent D processes often need filesystem, driver, or NFS troubleshooting rather than repeated kill -9.
top reports zombie count in the Tasks summary line (0 zombie on a healthy host).
Monitor and troubleshoot CPU and memory
Live sorting is where top command fits into the workflow. Interactive top refreshes continuously; batch mode prints one screen for logs and scripts.
top calculates per-process and CPU-state percentages between refreshes. Discard the first batch frame and read the second for a clearer troubleshooting sample:
top -b -d 1 -n 2 -o %CPU | awk 'BEGIN { frame=0 } /^top -/ { frame++ } frame==2' | head -15top - 18:48:42 up 1 day, 8:40, 4 users, load average: 2.56, 1.52, 1.44
Tasks: 307 total, 5 running, 302 sleeping, 0 stopped, 0 zombie
%Cpu(s): 10.9 us, 3.9 sy, 0.0 ni, 54.1 id, 0.0 wa, 29.6 hi, 1.6 si, 0.0 st
MiB Mem : 6069.0 total, 1078.5 free, 3814.3 used, 1451.9 buff/cache
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
34559 root 20 0 5250536 2.0g 42116 S 102.1 33.5 52:07.23 hugo
44698 root 20 0 228412 3196 2936 R 82.4 0.1 0:03.52 proc-la+
53 root 39 19 0 0 0 S 1.1 0.0 0:11.93 khugepa+
33929 root 20 0 11.3g 47708 14452 S 1.1 0.8 0:48.06 node
44700 root 20 0 231596 5472 3364 R 1.1 0.1 0:00.03 topSort by resident memory when the symptom is RAM pressure:
top -bn1 -o %MEM | head -15top - 18:40:17 up 1 day, 8:32, 4 users, load average: 1.82, 1.72, 1.59
Tasks: 290 total, 2 running, 288 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.9 us, 1.7 sy, 0.0 ni, 92.9 id, 0.0 wa, 3.0 hi, 0.6 si, 0.0 st
MiB Mem : 6069.0 total, 1097.9 free, 3800.4 used, 1446.7 buff/cache
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
34559 root 20 0 5249960 2.0g 42084 S 0.0 34.1 46:50.47 hugoInspect the PID at the top of the %MEM list — here 34559 (hugo):
ps -p 34559 -o pid,user,stat,vsz,rss,pmem,etime,cmdPID USER STAT VSZ RSS %MEM ELAPSED CMD
34559 root Sl+ 5250856 2117860 34.0 54:46 hugo server --bind 0.0.0.0 --baseURL http://127.0.0.1:1313/ --port 1313RES / RSS is resident physical memory. VIRT / VSZ is the process virtual address space — it includes mappings that are not currently in RAM, so a large VIRT alone does not mean the process is using that much physical memory.
Read the load average line as runnable tasks using or waiting for CPU plus tasks in uninterruptible sleep (commonly waiting for I/O). Load is not normalized by CPU count — compare it with nproc on the host:
nproc3On a host where nproc returns 3, a load average near 3.0 represents roughly one runnable or uninterruptible task per available CPU on average. Interpret it together with CPU idle and I/O-wait values because load also includes tasks in D state. Linux load average counts runnable tasks and tasks waiting in uninterruptible sleep, not only the CPU run queue.
In interactive top, press P to sort by CPU and M to sort by memory. Adjust scheduler priority with nice or renice when you need to give a CPU-heavy process less favorable scheduling so competing processes receive more opportunity to run.
Use this sequence instead of jumping straight to kill -9:
- Confirm symptoms — slow shell, high load, or monitoring alert
- Identify candidates —
top -bn1 -o %CPUortop -bn1 -o %MEM - Inspect details —
ps -p PID -o pid,ppid,user,stat,etime,cmdand memory columns when RAM is the concern - Check service ownership —
systemctl status servicenamewhen the command is a daemon child - Send SIGTERM —
kill PIDorsystemctl stop servicenamefor unit-managed services - Verify recovery —
ps -p PID, load average, and application health
Killing a child process that a supervisor immediately respawns fixes nothing until you stop the parent service or unit.
Manage foreground and background jobs
Shell jobs belong to your current bash session. They are not the same as every process on the system.
Start a long command in the background with &:
sleep 300 &The shell prints a job number and PID. List session jobs:
jobs -l[1]+ 41217 Running sleep 300 &Bring a stopped or background job to the foreground with fg %1. Resume a stopped job in the background with bg %1. Press Ctrl+Z while a foreground job runs to stop it and return control to the shell — then use bg or fg.
nohup ignores hangups but does not put a command in the background by itself — the trailing & does that:
nohup sleep 600 >/tmp/sleep-600.log 2>&1 &disown removes a background job from the shell's job table without killing the process. System daemons started by systemd are outside this job table entirely.
Send signals to processes
Processes react to signals. The kill and pkill reference covers every signal name; this workflow uses the common ones first.
| Signal | Number | Typical use |
|---|---|---|
SIGTERM |
15 | Polite shutdown — default for kill |
SIGKILL |
9 | Forced kill — cannot be caught or ignored |
SIGHUP |
1 | Hangup — daemons often reload or exit |
Stop a known PID with SIGTERM — replace 43175 with the PID you identified through ps, pgrep, or top:
kill -TERM 43175When you know the PID, prefer kill PID or kill -TERM PID over broad pkill -f patterns that can match multiple command lines. killall signals processes by executable name — use carefully on shared hosts because it matches every process with that name.
Verify the process exited:
ps -p 43175 -o pid,tty,time,cmdPID TT TIME CMDOnly the header row remains when the PID no longer exists. Reserve kill -9 or pkill -9 for processes that ignore SIGTERM after you have identified the correct PID.
For a background job in your shell, run sleep 300 &, list with jobs -l, then kill %1 or kill the PID from jobs -l.
Process management quick reference
| Task | Command |
|---|---|
| Full process list | ps aux or ps -ef |
| Preview name matches | pgrep -af pattern |
| One PID details | ps -p PID -o pid,ppid,user,stat,etime,cmd |
| Memory per PID | ps -p PID -o pid,user,stat,vsz,rss,pmem,etime,cmd |
| Live CPU sort | top then P, or second-frame top -b -d 1 -n 2 -o %CPU |
| Live memory sort | top -bn1 -o %MEM |
| CPU count for load context | nproc |
| Background job | command & |
| List shell jobs | jobs -l |
| Survive SSH logout | nohup command >/path/log 2>&1 & |
| Polite stop | kill PID or kill -TERM PID |
| Force stop (last resort) | kill -9 PID |
| Process tree | pstree -p or ps -ef --forest |
| Service-owned process | systemctl status unit then systemctl stop unit |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
High CPU, one PID in top |
Runaway user script or worker | ps inspect; kill -TERM; verify; use -9 only if needed |
| Process returns immediately after kill | Parent respawns child | Stop systemd unit or parent supervisor, not only the child PID |
Zombie listed in ps |
Parent not calling wait() |
Restart parent service or fix application; do not kill the zombie |
D state will not die |
Stuck kernel I/O | Diagnose storage/NFS/driver; SIGKILL may not help until I/O completes |
| Background job dies on SSH logout | SIGHUP to session | nohup … &, disown, or run under systemd |
kill: Operation not permitted |
Different user or capability | Run with sudo or signal as root |
References
- ps(1) — procps-ng — process status
- pgrep(1) — find processes by name
- top(1) — live process display
- pstree(1) — process tree
- signal(7) — Linux signal overview
- kill(1) — send signals to processes
- GNU Coreutils — nohup invocation — ignore hangups on disconnect
- bash(1) job control — jobs, fg, bg, and disown
Summary
Linux process management is a chain: list with ps aux or ps -ef, confirm load and CPU or memory with top, read STAT and PPID before you signal anything, and stop services at the systemd unit when a supervisor keeps respawning workers.
Default to SIGTERM through kill, then verify with ps -p. Zombies are unreaped exit statuses — fix the parent. D state means kernel I/O may block even SIGKILL until the operation completes or fails. Shell jobs (jobs, fg, bg) apply only to your session; top normally displays system-wide tasks.
When CPU contention is chronic, inspect priority with ps -o ni and consider nice and renice to give a heavy process less favorable scheduling before you terminate production workloads.

