Linux memory management in one sentence: the kernel uses every bit of RAM your programs aren’t using as disk cache, and hands it back the moment a program needs it. That’s why free often shows almost no “free” memory on a perfectly healthy machine. The number you actually care about is available, not free.
Below I show that with real numbers from an 8 GB Ubuntu 24.04 box, then cover swap, overcommit, the OOM killer, and the commands I reach for when a server starts running out of memory.
The Short Version
- Run
free -hand look at the available column. That’s how much memory new programs can get. - High buff/cache is good. It’s file cache the kernel drops instantly when needed.
- Swap being used a little isn’t a problem. Swap being read and written constantly (
si/soinvmstat) is. - If processes vanish without a trace, check for the OOM killer:
journalctl -k | grep -i "out of memory".
Linux Memory Management Basics
Four terms come up constantly:
- Physical memory: the RAM sticks in the machine.
- Virtual memory: the private address space every process sees. The kernel maps it onto physical RAM (and swap) behind the scenes.
- Kernel space: memory the kernel reserves for itself.
- User space: everything your applications use.
Reading free -h: Is My RAM Actually Full?
This is the question that brings most people here, so let’s answer it with real output. Here’s a fresh 8 GB Ubuntu 24.04 machine doing nothing:
$ free -h
total used free shared buff/cache available
Mem: 7.8Gi 526Mi 7.3Gi 13Mi 200Mi 7.3Gi
Swap: 0B 0B 0B
Now I write a 2 GB file to disk and run free -h again:
$ free -h
total used free shared buff/cache available
Mem: 7.8Gi 546Mi 5.3Gi 13Mi 2.2Gi 7.3Gi
Swap: 0B 0B 0B
“Free” dropped by 2 GB. Nothing was wrong. The kernel just kept that file in RAM as cache in case I read it again. Look at available: still 7.3 GB, because cache gets thrown away the moment a program asks for memory.
Compare that to a program actually allocating 3 GB:
$ free -h
total used free shared buff/cache available
Mem: 7.8Gi 3.5Gi 4.3Gi 13Mi 202Mi 4.3Gi
Swap: 0B 0B 0B
This time used went up and available went down. That’s real memory pressure. Here’s the cheat sheet I wish I’d had years ago:
| Column | What it means | Should you worry? |
|---|---|---|
| used | Memory held by processes and the kernel | Only together with low available |
| free | RAM doing literally nothing | No. Low free is normal and good |
| buff/cache | File cache, dropped on demand | No. This is the “Linux ate my RAM” column |
| available | What new programs can get without swapping | Yes. This is the one to watch |
| Swap used | Pages moved out of RAM at some point | Only if vmstat shows constant si/so |
My rule of thumb: if available stays above about 10 to 15 percent of total under normal load, the box is fine. If it sits near zero and swap is busy, you need more RAM or fewer things running.
Understanding Virtual Memory
Every process thinks it has a big, private, continuous block of memory. It doesn’t. Memory is split into pages (4 KB on most systems), and the kernel keeps a page table per process that maps virtual addresses to wherever the data really is: a spot in RAM, a page in swap, or a file on disk that hasn’t been loaded yet.
That’s also why a process’s virtual size (VIRT in top) can be huge while its real usage (RES) is small. VIRT counts everything it has mapped. RES counts what’s actually sitting in RAM.
The Swap Space
Swap is disk space the kernel uses to park memory pages that haven’t been touched in a while. It keeps a box alive under pressure, but it’s far slower than RAM, so a machine that swaps constantly feels like it’s wading through mud.
# show swap devices and usage
swapon --show
# how eager the kernel is to swap (default 60)
cat /proc/sys/vm/swappinessCode language: PHP (php)
On a server with plenty of RAM, I lower swappiness so the kernel prefers dropping cache over swapping out applications:
# apply now
sudo sysctl vm.swappiness=10
# keep after reboot
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.confCode language: PHP (php)
Memory Allocation in Linux
1. Dynamic Memory Allocation
Programs ask for memory at runtime (malloc in C, or the runtime does it for you in Python, Node or Java). The kernel hands out virtual pages right away but only backs them with real RAM when the program first writes to them.
2. Memory Overcommit
Because of that lazy behavior, Linux happily promises more memory than it has. The policy lives in /proc/sys/vm/overcommit_memory:
| Value | Behavior |
|---|---|
| 0 (default) | Heuristic. Refuses obviously impossible requests, allows the rest |
| 1 | Always say yes. Some databases and Redis setups recommend it |
| 2 | Strict. Never promise more than swap plus a ratio of RAM |
Leave it at 0 unless software you run tells you otherwise. The catch with overcommit is that when everyone actually uses what they were promised, something has to die. That’s the OOM killer’s job.
3. Page Cache
The page cache is the buff/cache column from earlier. Every file you read or write passes through it, so the second read comes from RAM instead of disk. You saw it grow by 2 GB in the example above without hurting anything.
Monitoring Memory Usage
Using top
Run top and press Shift+M to sort by memory. The RES column is what each process really holds in RAM. htop shows the same thing with less squinting.
# top 10 processes by memory, no interactive UI
ps aux --sort=-%mem | head -n 11Code language: PHP (php)
Using vmstat
vmstat is the fastest way to see if a machine is swapping right now. Here it is on the same idle box, one sample per second:
$ vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
0 0 0 7698660 1472 204332 0 0 272 18 205 0 2 0 98 0 0 0
0 0 0 7701036 1472 204516 0 0 0 40 135 108 1 0 100 0 0 0
0 0 0 7703584 1472 204516 0 0 0 0 195 204 1 0 99 0 0 0
Watch si (swap in) and so (swap out). Zeros are healthy. Numbers that stay above zero second after second mean the machine is short on RAM.
Reading /proc/meminfo
Everything free shows comes from here. The lines worth knowing:
$ grep -E 'MemTotal|MemFree|MemAvailable|^Cached|SwapTotal|SwapFree|Dirty' /proc/meminfo
MemTotal: 8223864 kB
MemFree: 7699260 kB
MemAvailable: 7685080 kB
Cached: 199564 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 128 kBCode language: JavaScript (javascript)
MemAvailable is the kernel’s own estimate of usable memory, and it’s what the available column in free shows. If you script memory alerts, alert on MemAvailable, never on MemFree.
Understanding the OOM Killer
When RAM and swap are both exhausted, the kernel’s Out Of Memory killer picks a process and kills it to save the system. It usually picks the biggest memory user, which is often exactly the database or app you cared about most.
If a process just disappeared, check whether the OOM killer got it:
journalctl -k | grep -i "out of memory"
# or
sudo dmesg -T | grep -i -E "out of memory|killed process"Code language: PHP (php)
You’ll see a line like Out of memory: Killed process 1234 (java). To make a critical process less likely to be picked, lower its OOM score:
# -1000 means never kill, 1000 means kill first
echo -500 | sudo tee /proc/<PID>/oom_score_adjCode language: PHP (php)
For a systemd service, set OOMScoreAdjust=-500 in the unit file instead, so it survives restarts.
Common Memory Issues and Solutions
Memory Leaks
The signature of a leak: one process’s RES climbs steadily for hours or days and never comes back down. Track it over time:
# print RSS in KB for a PID every 60 seconds
while true; do ps -o rss= -p <PID>; sleep 60; doneCode language: PHP (php)
For C and C++ programs, valgrind --leak-check=full ./program shows where the leaked memory was allocated. For everything else, restarting the service buys time while you find the bug.
High Memory Usage
First check whether it’s real. If available is healthy, high used plus cache is just Linux doing its job. If available is low, find the culprit with ps aux --sort=-%mem | head and decide whether to limit it, move it, or add RAM.
Practical Memory Management Examples
Setting Process Memory Limits
The modern way is a cgroup limit through systemd. This runs a command with a hard 500 MB cap:
sudo systemd-run --scope -p MemoryMax=500M ./my-program
For a service, add MemoryMax=500M under [Service] in its unit file. When the process goes over, only that service gets killed, not something random on the box. If systemd units are new to you, my systemd beginner’s guide covers them.
Clearing Page Cache
You can force the kernel to drop its cache:
sync
echo 3 | sudo tee /proc/sys/vm/drop_cachesCode language: PHP (php)
Honest opinion: you almost never should. It makes free look nicer for a minute and makes the next few disk reads slower. The only real use is benchmarking disk speed with a cold cache.
Advanced Memory Concepts
Transparent Huge Pages (THP)
THP lets the kernel use 2 MB pages instead of 4 KB ones, which cuts page table overhead. Some databases recommend turning it off because it can cause latency spikes. Check the current mode with:
cat /sys/kernel/mm/transparent_hugepage/enabled
Memory Cgroups
Cgroups are what Docker, Kubernetes and systemd use under the hood to cap memory per container or service. The MemoryMax example above is a cgroup limit. A container that hits its limit gets OOM-killed inside its own cgroup, while the host keeps running.
FAQ
Why does Linux use all my RAM?
It’s using spare RAM as file cache. That memory shows up as buff/cache and is released the moment a program needs it. Check the available column, not free.
What’s the difference between free and available memory in Linux?
Free is RAM doing nothing at all. Available is free plus the cache the kernel can drop without swapping. Available is the number that matters.
Is it bad if Linux is using swap?
Not by itself. A few hundred MB of swap used is normal. Constant swap activity in vmstat (si/so above zero every second) is the real warning sign.
How do I see which process uses the most memory?
Run ps aux --sort=-%mem | head, or open top and press Shift+M.
Further Learning
If you want to see memory shared between processes in practice, my Linux shared memory tutorial walks through a working example. The kernel’s own memory management documentation goes as deep as you’ll ever need.
Give thanks