Quick Summary – Linux Process Management
Observe before intervening. Use ps for a snapshot, top for live resource use, and kill for a controlled signal after you have verified the process identity.
- Verify identity — Check the PID, owner, full command line, parent process, and service manager before stopping anything.
- Use ps for detail — Choose explicit columns and sort by CPU or memory to build a useful process snapshot.
- Watch live pressure — Compare load, CPU, memory, swap, process state, and steal time instead of relying on one number.
- Prefer SIGTERM — Give the application a chance to close connections and clean up before considering SIGKILL.
- Inspect context — Read logs and check open files, sockets, parent processes, and service policies.
- Automate carefully — Automate observation first and keep broad process termination behind explicit checks.
When a VPS slows down, do not begin with a reboot. Use ps for a precise snapshot, top for live CPU and memory behavior, and kill for controlled signals. Before touching a PID, confirm its owner, command line, parent, and service manager; that short pause has saved me from more than one bad decision.
Table of Contents
- Why I check processes before I reboot
- Listing processes with ps
- Watching live usage with top
- What CPU, memory, and process states actually tell you
- Trace the parent process and inspect its files
- Choosing a signal with kill
- Bulk termination needs a narrow match
- Automate observation before termination
- A practical order when a VPS becomes slow
- Before You Stop a Linux Process
- Frequently Asked Questions
- Sources
Why I check processes before I reboot
A slow VPS creates a strong urge to type reboot and move on. I know that urge well. On my Debian ThinkPad, I once saw a worker stuck in D state and assumed it was simply misbehaving. It was waiting on storage, so repeated signals would not have fixed the real problem.
When a web server stops responding or the load average rises, I first check which processes are running, who owns them, how much CPU and memory they use, and which parent process started them. Rebooting may hide the symptom for a few minutes. Process inspection gives me a chance to understand it.
ps gives me a snapshot, top shows live activity, and kill sends a signal rather than blindly forcing a process to disappear. Used together, these commands let you intervene with evidence.
My first rule: verify the PID, user, complete command line, and parent process before stopping anything.
Listing processes with ps
ps shows the processes that exist when you run it. Without options, it usually shows processes associated with your current terminal:
ps
PID TTY TIME CMD
8421 pts/0 00:00:00 bash
9134 pts/0 00:00:00 ps
PID is the process ID. TTY identifies the terminal, TIME shows accumulated CPU time, and CMD shows the command name. To view processes from all users, I commonly use one of these:
ps aux
ps -ef
ps aux uses BSD-style options and puts CPU and memory percentages near the front. ps -ef uses UNIX-style options and includes the parent PID and start time. Do not casually mix the two forms: ps aux and ps -aux are not equivalent commands.
Finding one process
A long process list is easier to search, but the search itself needs care. The grep process can appear in its own output:
ps aux | grep '[n]ginx'
pgrep -a nginx
pidof nginx
pgrep -a prints matching PIDs with their command lines. pidof is convenient when I only need the PIDs belonging to a service. When I am investigating a resource alert, I usually ask ps for specific columns:
ps -eo pid,ppid,user,%cpu,%mem,stat,lstart,cmd --sort=-%cpu | head -n 15
PPID is the parent process ID, STAT describes the current state, and LSTART shows when the process started. The negative sort puts the highest CPU consumers first. Replace --sort=-%cpu with --sort=-%mem when memory is the concern.
That one command is often my first useful snapshot. It is much better than guessing from a dashboard that only says “the server is slow.”
Watching live usage with top
top refreshes the process list and keeps CPU, memory, load average, and active processes on one screen:
top
The three load average values represent runnable or waiting work over the last 1, 5, and 15 minutes. Compare them with the number of vCPUs. A load of 2.0 is not automatically alarming on an 8-vCPU VPS, while the same value means sustained pressure on a 1-vCPU VPS.
These keys change the view while top is running:
Psorts by CPU usage.Msorts by memory usage.1shows individual CPU cores.ctoggles between the short name and full command line.Hshows or hides threads.kopens the signal prompt for a PID.qexits the program.
CPU percentage is only one clue. If one process stays near the top, the bottleneck may be computation. If memory usage rises while available memory falls, I look for memory pressure. Swap deserves its own check:
free -h
vmstat 1 5
free -h reports memory in readable units. In vmstat, persistent non-zero si and so values mean the system is moving pages into and out of swap. A slow VPS is not always suffering from one CPU-hungry process.
On a virtual machine, I also watch st in top. That is CPU time stolen by the hypervisor. If application processes look ordinary but the VPS remains slow, provider-side contention or a CPU limit may be involved.
What CPU, memory, and process states actually tell you
A process using 100 percent CPU generally occupies one logical processor completely, although tools present percentages differently. On a multi-core host, the number is not automatically the percentage of the entire machine.
For memory, RES is the portion currently resident in RAM, VIRT is the virtual address space, and SHR is the shareable portion. A large VIRT value does not mean the process consumes the same amount of physical memory. I compare RES with system-wide available memory and swap activity.
Process state adds another useful clue:
Rmeans running or ready to run.Smeans interruptible sleep.Dmeans uninterruptible sleep, commonly during I/O.Zmeans the process has exited but its parent has not collected its status.
Use this to find processes in D or Z state:
ps -eo pid,stat,wchan:32,cmd | awk '$2 ~ /^D/ || $2 ~ /^Z/ {print}'
A process in D state may be waiting for a disk, a network filesystem, or another kernel-level I/O operation. Repeatedly sending signals is usually not the answer. For a zombie, inspect its parent process; the zombie is often only the visible remainder of the problem.
When I hit the stuck worker on my test machine, its name looked suspicious enough to kill. The D state changed my plan. I checked the storage path first, and that saved me from treating an I/O problem as an application problem.
Example
A process in D state is usually waiting in the kernel, often on storage or another I/O operation. Repeated signals are less useful than finding the underlying I/O delay.
Trace the parent process and inspect its files
Every process has a PID and, in normal circumstances, a parent PID. The process tree tells you why a service has several workers and whether a process is likely to return after it exits:
pstree -aps 9134
ps -o pid,ppid,user,lstart,cmd -p 9134
pstree -aps shows the chain leading to the selected PID. The ps -o form prints only the columns I request, which keeps the output readable during an incident.
To inspect files and sockets opened by a process:
lsof -p 9134
ls -l /proc/9134/fd
tr '\0' ' ' < /proc/9134/cmdline; echo
The /proc filesystem exposes process information through a kernel interface. Links under /proc/PID/fd point to open files, sockets, and pipes. Access to another user’s process details may be restricted, so not every inspection requires root access.
When I need to see which process owns a listening port, ss is usually enough:
ss -ltnp
ss -ltnp | grep ':8080'
The output can separate an application problem from a reverse-proxy routing mistake. Nginx listening on ports 80 and 443 while an application listens on 127.0.0.1:8080 is a normal design. It becomes a problem only when the proxy points somewhere else, or when nothing is listening on the upstream port.
Before I stop an unfamiliar process, I record its owner, parent, full command line, open files, and listening sockets. That takes less time than explaining why the wrong service disappeared.
From the field
I once followed a stuck worker on my Debian test machine and nearly treated it like a normal runaway process. Its D state pointed me toward storage waits instead, which reminded me to read process state before reaching for kill.
Choosing a signal with kill
The command called kill sends a signal to a PID. It does not always force the process to close. With no signal specified, it sends SIGTERM, signal 15, which gives an application the opportunity to close connections and clean up:
kill 9134
kill -TERM 9134
kill -15 9134
These commands send the same signal. Check the result afterward:
kill -0 9134 && echo 'PID exists or is accessible' || echo 'PID not found or permission denied'
kill -0 does not terminate anything. It checks whether the PID exists and whether you can send it a signal. A successful check does not prove that the application is healthy; it only confirms that the PID is present and accessible.
If the process ignores SIGTERM, read the application and system logs before escalating. The last resort is SIGKILL:
kill -KILL 9134
kill -9 9134
SIGKILL cannot be caught or deferred. Cleanup code will not run, so open connections, temporary files, and application state may be left in an unexpected condition. I am especially careful with databases, file writers, and queue workers.
For a process controlled by a service manager, use that interface instead of killing the PID directly:
sudo systemctl status nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
If systemd is configured to restart the service, a directly killed process may return a few seconds later. That is often the service policy working as configured.
Order matters: send SIGTERM, verify the shutdown, and use SIGKILL only when graceful termination has failed and you understand the consequences.
Caution
SIGKILL cannot be caught and gives the application no chance to clean up. Use it only after graceful termination has failed and you understand what may be left behind.
Bulk termination needs a narrow match
pkill and killall can stop multiple processes by name. That makes them useful, but dangerous when the match is broad:
pgrep -a worker
pkill -TERM -u appuser -f '/opt/app/worker.py'
-u limits the match to a user, while -f searches the complete command line instead of only the short process name. Run pgrep -a first and inspect every result. A matching substring can select a process you did not mean to touch.
I keep long investigations inside tmux. An SSH disconnect should not erase the terminal where I am watching logs or waiting for a service to stop. A background process is not automatically a service, though; production workloads are easier to observe when systemd, Supervisor, or the application’s own service mechanism owns them.
When you cannot identify a process, pause. Display its command line, check the user, find the parent, inspect files and sockets, and read the relevant logs. On WordPress VPSs, PHP-FPM workers, web requests, and database waits need to be considered together. Killing the worker with the highest CPU usage may only remove the most visible symptom.
Tip
Run pgrep -a before pkill. Seeing the exact command lines turns a broad pattern into a deliberate match.
Automate observation before termination
If I repeat the same process check for a third time, I consider writing a small Bash Script. The first version should report what it finds. Automatic termination should not be the default.
#!/usr/bin/env bash
set -u
pattern="/opt/app/worker.py"
if ! pgrep -af -- "$pattern"; then
echo "Process not found: $pattern" >&2
exit 1
fi
echo "Verify the PID and command line first. No automatic kill was applied."
set -u treats unset variables as errors. This script intentionally does not terminate anything. That restraint is useful: a mistaken pattern should produce a report, not a service outage.
Ansible is useful when I need the same observation across several VPSs. For a one-time command on one host, opening a YAML file can be unnecessary ceremony. If monitoring reports process count, CPU, memory, and service state, include the PID, command name, and last restart time where they are available.
A practical order when a VPS becomes slow
I use this sequence instead of reaching for a reboot:
- Run
uptimeto see load average and uptime. - Run
free -hto check available RAM and swap. - Use
toporpsto find the leading CPU and memory consumers. - Verify the process with
ps -o pid,ppid,user,stat,cmd -p PID. - Read
journalctl -u service-nameand the application logs. - Check
systemctl status service-nameand the restart policy if systemd owns the service. - Use
systemctl stopor sendSIGTERMbefore consideringSIGKILL. - Measure the system again after the process exits.
Disk pressure can change process behavior too. If /var is full, applications may fail to write logs, lock up, or stop creating workers. Check df -h, ncdu, and log rotation together. Killing a process does not make a full filesystem less full.
| Tool | Best use | Watch for |
|---|---|---|
ps |
Detailed snapshot and custom columns | It does not refresh live |
top |
Live CPU, memory, and load monitoring | Values need system context |
kill |
Sending a signal to a specific PID | SIGKILL skips cleanup |
pgrep |
Searching for PIDs and command lines | Keep the pattern narrow |
Safe process management is not about finding the largest number and killing it. Measure first, identify the process, inspect its context, choose the least destructive action, and measure again.
The next time a VPS alarm wakes you up, give yourself one quiet minute before typing reboot. Start with the PID. It usually has more to say than the load average.
Before You Stop a Linux Process
- Run ps or top and record the suspicious PID.
- Confirm the process owner and complete command line.
- Find the parent PID and check whether a service manager owns it.
- Inspect process state, CPU, memory, open files, and sockets.
- Read the relevant application and system logs.
- Send SIGTERM or use systemctl stop before considering SIGKILL.
- Measure the system again after the process exits.
Keep these commands close during the next VPS incident, but begin with evidence rather than a reboot. A careful PID check is usually faster than recovering from an unnecessary process kill.
Frequently Asked Questions
What is the difference between ps and top?
ps prints a snapshot at the moment you run it and is useful for custom columns, filtering, and scripts. top refreshes continuously and is better for watching changing CPU, memory, load, and process state. I often use top to notice a problem, then ps to capture the exact command line, parent PID, and start time.
What does kill do in Linux?
kill sends a signal to a process ID; it does not always force the process to disappear. With no signal specified, it sends SIGTERM, allowing the application to shut down cleanly. kill -9 sends SIGKILL, which cannot be handled or delayed, so cleanup code will not run. Verify the result afterward.
Is a high CPU process always the cause of a slow VPS?
No. It may be the cause, but it may also be a symptom of slow storage, repeated errors, a busy queue, or a downstream dependency. Compare process CPU with load average, available memory, swap activity, I/O wait, logs, and process state. On a VPS, check CPU steal time because host contention can make ordinary processes appear slow.
What does a process in D state mean?
A process in D state is in uninterruptible sleep, commonly waiting for disk or network-storage I/O. Signals usually cannot make it exit until that kernel wait completes. Instead of repeatedly using kill, inspect storage latency, mounted filesystems, network storage, and kernel logs. If the condition persists, the underlying device or I/O path needs attention.
Why should I avoid kill -9 when stopping a service?
SIGKILL ends a process without giving it an opportunity to close connections, flush data, remove temporary files, or finish a transaction. A database or queue worker may leave recovery work behind. Try the service manager or SIGTERM first, wait for shutdown, inspect logs, and use SIGKILL only when graceful termination has genuinely failed.
How can I safely kill processes by name?
Preview the match before terminating anything. Run pgrep -a name or a similarly narrow query, verify the user and complete command line, then use a restricted pkill pattern if necessary. The -f option matches the full command line and can select more processes than expected. For production services, prefer systemctl stop so the service policy remains visible.
Sources
- Linux Kernel Documentation – The /proc Filesystem — docs.kernel.org