High CPU or Memory on a Linux Server: How to Find the Cause
Practice4 minInnovialabs editorial team
In short
Start with top or htop to spot the culprit, use vmstat and iostat to tell CPU load from disk waits, and check free and dmesg to see whether memory is short and the OOM killer has fired.
The short answer
Diagnosis order:
toporhtop: who is using CPU and memory right now.vmstat 1: what limits the system, CPU, memory or I/O.iostat -x 1: whether the disk is the bottleneck.free -handdmesg: how much memory is really available and whether the kernel killed processes.ps: history and details of a specific process.
vmstat and iostat usually come with the procps and sysstat packages.
How to read load average
top and uptime show three numbers: the average load over 1, 5 and 15 minutes. It is the number of processes running or waiting to run. On Linux it also counts processes waiting for disk (state D).
- Compare load average with the number of cores (
nproc). On 4 cores a value around 4 means full utilization, noticeably higher means a queue. - If load is high but the CPU is mostly idle, look at disk or network, not the processor.
- A rising first number with calm others is a fresh spike, not a chronic issue.
Step 1. top and htop
In top, press P to sort by CPU and M to sort by memory. In htop, click a column or press F6.
Watch the %Cpu(s) line:
| Field | What a high value means |
|---|---|
us | application code: heavy computation, an infinite loop |
sy | kernel: many system calls, network traffic |
wa | I/O wait: slow or overloaded disk |
st | steal: neighbors on the hypervisor take CPU from your VPS |
High st on a virtual machine cannot be fixed inside the OS; it is a question for the host or your plan.
Step 2. vmstat and iostat
vmstat 1 5
- Column
ris the CPU run queue. Consistently above the core count means not enough CPU. bis processes blocked on I/O.siandsoare swap-in and swap-out. Constant non-zero values mean memory is short.
iostat -x 1 5
High %util and large await for a disk mean it cannot keep up. Find out who writes: iotop lists processes by I/O volume.
Step 3. Memory: free, swap and the OOM killer
free -h
Look at available, not free. Linux uses spare memory for file cache (buff/cache) and hands it to applications on demand, so a small free value is normal.
Swap is backup memory on disk. A little used swap is fine. The problem is constant swapping (si/so in vmstat), which makes the system crawl.
When memory and swap run out, the kernel starts the OOM killer and kills the process with the highest score. Check:
dmesg -T | grep -i -E "killed process|out of memory"
journalctl -k | grep -i oom
If an app "restarts by itself" with nothing in its own logs, the OOM killer is a frequent reason.
Step 4. ps: process details
ps aux --sort=-%cpu | head -n 10
ps aux --sort=-rss | head -n 10
ps -o pid,etime,rss,cmd -p 1234
RSS is the real memory in use, etime is how long the process has been running. If a process's RSS only grows over time, suspect a leak.
Handling a runaway process
- Identify it:
ps -fp PID,ls -l /proc/PID/exe, and which service it belongs to (systemctl status PID). - Collect evidence before restarting: app logs,
journalctl -u service, when the problem started. A restart wipes the clues. - Lower its priority if the process is needed but disruptive:
renice +10 -p PID. - Stop it gracefully:
kill PID(SIGTERM) first, andkill -9 PIDonly if that fails. - If it is a cron job or an unknown process, check where it was launched from. An unexpected high-CPU process can be a miner left after a break-in.
Memory leak: step by step
- Confirm the growth: record the process RSS at intervals (
psin a loop or your monitoring). - Tie the growth to events: a deploy, a specific route, a background job.
- Limit the damage: a memory cap via systemd (
MemoryMax=) or Docker (mem_limit), so only that service fails, not the whole server. - A scheduled restart works as a stopgap, not a fix.
- Find the cause with your language's profiler: unbounded caches, unclosed connections, event listeners nobody removes.