Learn how to identify which process is consuming your Linux server's CPU or memory using top, ps aux, and sort, then safely terminate runaway or zombie processes without guessing.
Prerequisites
- SSH access to a Linux server
- sudo or root privileges
- Basic familiarity with the terminal
What this solves
A server that suddenly feels slow is almost always caused by one or two processes consuming most of the CPU or memory. This tutorial shows you how to read load average and process metrics, find the exact culprit with top and ps aux, and decide whether to kill it or investigate further.
This works the same way whether you are troubleshooting a web server, a database host, or a background worker.
Step-by-step diagnosis
Check the load average first
Load average shows how many processes are waiting for CPU time, averaged over 1, 5, and 15 minutes. On a system with 4 CPU cores, a load average above 4 means processes are queuing for CPU.
uptimeCheck how many CPU cores you have to put that number in context.
nprocOpen top for a live view
top gives you a real-time, auto-refreshing list of processes sorted by CPU usage by default.
topInside top, press Shift+M to sort by memory usage instead of CPU, and press Shift+P to go back to sorting by CPU. Press q to quit.
Understand RES vs VIRT
top shows several memory columns that are easy to misread. VIRT is the total virtual memory a process has mapped, including shared libraries and memory it has reserved but not touched. RES is the actual physical RAM the process is using right now, which is the number that matters for diagnosing memory pressure.
| Column | Meaning | When to worry |
|---|---|---|
| VIRT | Total virtual memory mapped | Rarely, it is often inflated by shared libraries |
| RES | Physical RAM currently in use | Yes, this is real memory pressure |
| SHR | Memory shared with other processes | Subtract from RES to estimate unique usage |
| %MEM | RES as a percentage of total system RAM | Yes, quick way to spot a memory hog |
List processes with ps aux
ps aux gives you a one-time snapshot of every process, which is easier to pipe, grep, and sort than top's live view.
ps auxThe columns you care about are %CPU, %MEM, RSS (resident memory in KB), and COMMAND.
Sort ps aux by CPU usage
Sort the output by the %CPU column, descending, and show the top 10 processes.
ps aux --sort=-%cpu | head -n 11The negative sign before %cpu means descending order. Remove it to sort ascending.
Sort ps aux by memory usage
Use the same pattern with %mem to find the biggest memory consumers.
ps aux --sort=-%mem | head -n 11Filter for a specific process by name
If you already suspect a service, such as nginx or mysqld, filter ps output directly instead of scanning the whole list.
ps aux | grep -i mysqld | grep -v grepThe second grep removes the grep command itself from the results.
Identify zombie and defunct processes
A zombie process has finished executing but its exit status has not been collected by its parent process, leaving an entry in the process table. Zombies do not consume CPU or memory, but a large number of them can indicate a buggy parent process that never calls wait().
ps aux | awk '$8 ~ /Z/ {print}'If you see zombies, the real fix is restarting the parent process, since you cannot kill a zombie directly, it is already dead and waiting to be reaped.
ps -o ppid= -p <zombie_pid>Check per-process memory breakdown
For a deeper look at one process, including shared vs private memory, use the proc filesystem.
cat /proc/<pid>/status | grep -E 'VmRSS|VmSize|VmSwap'Find out which user is running the heaviest processes
Sometimes the question is not which process, but which user or application owns it.
ps aux --sort=-%mem | awk 'NR==1 || NR<=10 {print $1, $2, $3, $4, $11}'Terminate a runaway process safely
Always try a graceful termination first with the TERM signal, which asks the process to clean up and exit on its own.
kill -15 <pid>Wait a few seconds and check if it is still running. Only use SIGKILL if the process ignores SIGTERM, since SIGKILL gives it no chance to close files or save state.
kill -9 <pid>Kill all instances of a process by name
If a process is spawning multiple children, such as a misbehaving script or a leaked worker pool, killall targets every process matching a name.
killall -15 nodeAs with kill, escalate to SIGKILL only if the processes do not exit within a few seconds.
killall -9 nodeVerify your setup
After terminating or restarting a process, confirm the resource usage has actually dropped.
uptime
ps aux --sort=-%cpu | head -n 5
free -hfree -h shows total, used, and available memory in human-readable units, which confirms whether memory was actually released.
When to investigate further vs when to restart a service
If a process is consuming high CPU briefly during a known workload, such as a backup job or a batch import, that is expected behavior, not a problem. Investigate further when CPU or memory usage climbs steadily over hours or days with no corresponding increase in traffic, since that pattern usually means a memory leak or an infinite loop in application code.
Restarting the service is the right short-term fix when you need the system responsive again immediately and you already know the service has a known leak that will be patched later. It is not a substitute for finding the root cause, since the same process will eventually degrade again.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| top shows 100%+ CPU for one process | Process is using more than one core's worth of CPU time | Divide %CPU by number of cores with nproc to get true utilization |
| Process reappears after kill | It is managed by systemd or a supervisor and gets auto-restarted | Stop the service properly with sudo systemctl stop servicename instead of killing the PID |
| kill -9 does nothing | Process is in uninterruptible sleep (D state), usually waiting on I/O | Investigate the underlying disk or NFS issue, SIGKILL cannot interrupt D state |
| Many Z state processes | Parent process is not reaping finished children | Restart the parent process, you cannot kill a zombie directly |
| Free memory looks low but nothing seems to be using it | Linux uses spare RAM for disk cache, which is reclaimable | Check the available column in free -h, not the free column |
| Permission denied when killing a process | Process is owned by another user or root | Use sudo kill -15 <pid>, never run your whole shell as root to avoid this |
Next steps
- Configure Linux process monitoring with top, htop, and btop
- Fix high load average with low CPU usage on web servers
- Check disk space usage on Linux with df and du commands
- Find and kill processes using a specific port on Linux
- Configure Linux process resource monitoring and alerting with cgroups and systemd
- Set up Linux performance alerting with Prometheus node exporter