Readable learning overview

How to Diagnose CPU Bottlenecks and Memory Pressure in Linux

A beginner-friendly, production-safe guide to finding out whether a slow Linux server is struggling with CPU, memory, storage, or a runaway process.

Learn what the important Linux performance numbers mean, which commands to run first, and how to respond safely without making the incident worse.

Linux Troubleshooting 路 Updated 19 Jul 2026 路 11 min read 路 58 views

Handling a critical ticket while a production server is grinding to a halt is stressful. The fastest engineers are not the ones who type the most commands. They are the ones who preserve evidence, separate CPU pressure from memory and I/O pressure, and choose the lowest-risk action that restores service.

Read the dashboard as a set of clues

A high load average is not a complete diagnosis. Compare CPU, available memory, swap activity, I/O wait, processes, and logs before changing the system.

Start with the simple picture

A slow Linux server usually needs you to answer three questions:

  1. Is the CPU too busy? Think of the CPU as workers at a service counter. If every worker is busy and more work keeps arriving, a queue forms.
  2. Is the server running short of memory? Think of RAM as a fast work desk. When the desk is full, Linux may move less-used information to much slower disk space called swap.
  3. Are programs waiting for storage or another I/O operation? The CPU may not be busy at all; applications can still feel frozen while they wait for a slow disk, network storage, or heavy swapping.

Your goal is not to react to one large number. Your goal is to identify which of these three situations is delaying useful work.

Beginner glossary: the numbers you will see

TermMeaning in plain language
Load averageHow much work is running or waiting. The three values show averages for the last 1, 5, and 15 minutes.
usUser CPU time: applications such as Java, Node.js, Python, Nginx, or a database are using the CPU.
sySystem CPU time: the Linux kernel is busy doing work such as networking, storage operations, interrupts, or many system calls.
idIdle CPU time. A value close to zero means little CPU capacity is currently available.
waI/O wait: programs are waiting for storage or another I/O operation. High wa is not the same as high application CPU use.
availableMemory Linux can realistically provide to applications without heavy swapping. This is more useful than the free column.
si/soSwap in and swap out. Repeated values above zero can mean Linux is actively moving memory pages between RAM and disk.
PIDProcess ID: the unique number Linux assigns to a running process.
OOMOut Of Memory. Linux may kill a process when it cannot safely provide more memory.
Production rule: capture before you change

Record the timestamp, alert, affected service, current load, memory state, top processes, and recent kernel messages. A restart may restore service, but without evidence it can erase the path to the root cause.

The 60-second initial triage

Start with four commands. Run them one at a time and read the explanation below before trying more advanced tools.

uptime
free -h
top
vmstat 1 5
  • uptime shows the load average. Run nproc to see how many logical CPUs the server has.
  • free -h shows memory and swap in human-readable units. Focus first on the available memory.
  • top shows CPU fields and which processes are using the most CPU or memory. Press P to sort by CPU or M to sort by memory.
  • vmstat 1 5 takes five samples, one second apart. Ignore the first line because it summarizes activity since boot; use the later lines to see what is happening now.

Compare load average with the CPU count, but treat it as a clue. A load above the CPU count suggests a queue is building. The queue may be waiting for CPU time or may be blocked on I/O, so check us, sy, id, and wa before deciding.

SignalLikely directionConfirm with
High load, id near zero, high usAn application is keeping the CPU busyFind the top CPU process with top or ps
High load and high syThe Linux kernel is doing a lot of workCheck system calls, context switches, networking, and storage activity
High load and high waPrograms are waiting for storage or I/OCheck disk latency with iostat -xz and activity with pidstat -d
Low available memory with repeated si/soLinux is actively moving data between RAM and swapWatch several vmstat samples and identify growing processes
A service disappeared and the kernel logged a killed processLinux probably used the OOM killerCheck journalctl -k and record the killed process

Part 1: is the CPU the bottleneck?

A CPU bottleneck exists when runnable work consistently demands more compute time than the available CPUs can supply. A brief spike is not enough; look for sustained pressure that matches the user-visible slowdown.

1. Read the CPU fields correctly

vmstat 1 5
mpstat -P ALL 1 5
pidstat -u -w 1 5
  • us (user): application code is consuming CPU. Compression, encryption, query processing, garbage collection, loops, or expensive requests may be involved.
  • sy (system): the kernel is doing substantial work. Investigate syscalls, networking, interrupts, I/O, and context switching.
  • id (idle): close to zero across the observation window means little CPU capacity remains.
  • wa (I/O wait): the CPU is idle while tasks wait for I/O. This points away from pure compute saturation and toward storage or another blocking path.
  • r in vmstat: runnable processes. A sustained run queue above available CPUs supports a CPU contention diagnosis.

2. Isolate the process and thread

ps -eo pid,ppid,stat,comm,%cpu,%mem --sort=-%cpu | head -n 11
top -H -p <PID>
pidstat -u -w -p <PID> 1 5

For a multithreaded process such as Java, Node.js, Python workers, Nginx, or a database, the process total is only the first clue. Use the thread view to identify whether one thread is spinning, many workers are legitimately busy, or the process is spending time in context switches.

3. Check pressure, not just utilization

cat /proc/pressure/cpu
cat /proc/pressure/io

This is an optional advanced check. Pressure Stall Information (PSI) measures how much time programs lose while waiting for CPU, memory, or I/O resources. Rising CPU some averages mean at least some tasks are waiting for CPU time. Beginners can first become comfortable with top, free, and vmstat, then add PSI later.

4. Mitigate with the lowest-risk action

  1. Reduce incoming work: pause a batch, shed optional traffic, lower worker concurrency, or scale out if the platform supports it.
  2. Lower a non-critical process priority: sudo renice -n 19 -p <PID>. Verify the new priority and service impact.
  3. Constrain a known-safe workload: prefer service, container, or cgroup CPU limits. Temporary affinity such as sudo taskset -cp 0,1 <PID> can help in a controlled incident, but poor affinity choices can make latency worse.
  4. Stop gracefully: use the service manager or kill -TERM <PID>, wait, and confirm shutdown. Use kill -KILL <PID> only as a last resort because it prevents cleanup and can leave partial work behind.

Part 2: is memory pressure slowing the server?

Linux intentionally uses spare RAM for page cache, so the free column is not the number that matters most. Focus on available, active reclaim, swap-in and swap-out activity, pressure, process growth, and OOM events.

1. Confirm active pressure

free -h
vmstat 1 10
cat /proc/pressure/memory
pidstat -r 1 5

Allocated swap is not automatically a problem; Linux may leave cold pages in swap even after pressure has passed. Sustained non-zero si and so in vmstat, low available memory, elevated memory PSI, and slow I/O together are much stronger evidence of active thrashing.

2. Find the consumers and the growth pattern

ps -eo pid,ppid,stat,comm,rss,%mem --sort=-rss | head -n 11
pidstat -r -p <PID> 1 10
cat /proc/<PID>/status | egrep 'VmRSS|VmSwap|Threads'

One snapshot tells you who is large. Repeated samples tell you who is growing. Distinguish expected cache, a workload spike, too many workers, a process leak, and a restrictive container memory limit before deciding the fix.

3. Check for OOM killer intervention

journalctl -k -g 'oom|out of memory|killed process'
dmesg -T | grep -i -E 'oom|out of memory|killed process'

Record the killed PID, process name, cgroup or container, memory totals, and timestamp. If the host has free memory but a container is killed, inspect the workload's cgroup limit rather than assuming the entire server ran out of RAM.

4. Mitigate memory pressure safely

If you are a fresher or do not own the production service, collect the evidence and involve the service owner before changing limits, stopping processes, or adjusting OOM settings.

  1. Stop the growth: pause the leaking or non-critical workload, reduce concurrency, reject optional work, or scale capacity.
  2. Restart only with evidence: if an approved restart is the recovery action, capture diagnostics first and watch memory after recovery so a leak does not silently return.
  3. Protect critical services carefully: a temporary adjustment is echo -500 | sudo tee /proc/<PID>/oom_score_adj. For systemd services, use a reviewed OOMScoreAdjust= setting. Avoid blanket -1000 protection: making one process unkillable can force the kernel to kill another essential service.
  4. Fix the capacity or limit: tune heap and worker counts, correct cgroup limits, add memory, or repair the leak after service is stable.
Do not drop caches as a routine fix

echo 3 > /proc/sys/vm/drop_caches does not repair a memory leak and can create an I/O spike while useful cache is rebuilt. Reserve cache dropping for an approved diagnostic experiment with a clear hypothesis, not as a standard production response.

A production incident sequence you can reuse

  1. Declare impact: what is slow or unavailable, when it started, and which users or services are affected?
  2. Capture a baseline: timestamp, CPU count, load, CPU fields, available memory, swap activity, PSI, top processes, and kernel events.
  3. Classify the pressure: CPU queue, I/O wait, active memory reclaim, OOM, or a mixture.
  4. Identify the owner: process, thread, service, container, dependency, recent deployment, or workload change.
  5. Mitigate reversibly: shed work, lower priority, scale, or stop gracefully before considering forceful actions.
  6. Validate: repeat the same measurements and confirm both system signals and user experience improved.
  7. Preserve follow-up evidence: commands, timestamps, graphs, process IDs, logs, action taken, result, rollback path, and prevention item.
Remember this four-step pattern

Observe the symptom and metrics. Confirm the likely bottleneck with more than one signal. Act using the least risky approved change. Verify by repeating the same commands and checking the user experience.

Quick reference for the incident channel

GoalCommandWatch for
System overviewuptime; nproc; topLoad trend, run queue, CPU fields, dominant process
CPU by corempstat -P ALL 1 5One hot core versus host-wide saturation
Memory and I/O streamvmstat 1 10r, si/so, wa, CPU state
Pressure viewcat /proc/pressure/{cpu,memory,io}Short- and medium-window stall time
Process trendpidstat -u -r -d -p <PID> 1CPU, faults, RSS growth, reads, and writes
OOM auditjournalctl -k -g 'oom|killed process'Killed process, cgroup, timestamp, allocation failure

The key lesson

Do not optimize the loudest metric. Diagnose the resource that is making useful work wait. CPU utilization, load average, free memory, swap, and I/O wait become meaningful only when they agree with process trends, pressure data, logs, and the user-visible symptom. That evidence-first habit is what makes a Linux response fast, safe, and credible.

Recommended resources

Manual references stay pinned first, and AI adds extra official or trusted links matched to the lesson topic.

Related reading

These pages connect closely to the current lesson and help learners keep moving through the same subject cluster.