It's two in the morning. You run free -h on the server and see this:
total used free shared buff/cache available
Mem: 15Gi 14Gi 312Mi 180Mi 890Mi 620Mi
Swap: 2.0Gi 1.4Gi 600Mi
The free column is nearly zero, and swap is half full. The first reaction is that the server has run short and more RAM is needed. In most cases this conclusion is wrong, but not always. The difference between these two states is exactly what determines whether you need to spend money or change a setting.
The free column lies, read the available column
The Linux kernel doesn't like idle memory. Every file that's read, every block that comes from disk, is kept in buff/cache so it won't be read from disk next time. This memory isn't "used"; it's reclaimable. The moment a process needs it, the kernel takes it back in a fraction of a second.
The available column calculates exactly this: how much memory can reach a new process without going to swap. In the output above, free says 312 megabytes, but available says 620 megabytes. The second number is the one that matters.
So the first rule: if available is above 10 to 15 percent of total RAM and swap isn't constantly churning, your server doesn't have a memory problem. That 14 gigabytes of used is mostly cache, and that's its job.
When we actually have a shortage
Three signs that together mean a real problem:
- The
availablecolumn is below 5 percent of total RAM and decreasing across several consecutive samples. - The output of
vmstat 1 5shows a steady, non-zero number in thesiandsocolumns. That means the system is constantly swapping between RAM and swap. - In
dmesg -T | grep -i oomyou see a line likeOut of memory: Killed process 2841 (php-fpm).
If you have all three, the discussion is over. If you only have the first and swap is untouched, you're probably looking at a meaningless number.
This is where they go wrong: restarting the service instead of finding the consumer
A pattern I've really seen a lot: the site admin sees available is low, restarts MySQL, the number looks good for two hours and then comes back. The service had no problem at all; you just threw away the cache and forced the system to re-read everything from disk. And those two hours are exactly the time the cache was refilling.
The sign is that RAM usage after each restart climbs with roughly the same slope and stays flat at a specific ceiling. Find the real consumer with ps aux --sort=-rss | head -15, not with a restart. If a process like php-fpm or a WordPress plugin is at the top of the list and keeps growing, you have a memory leak there and that's what you need to fix.
Don't manually clear buff/cache
The command sync; echo 3 > /proc/sys/vm/drop_caches works and is tempting. Don't do this on a production server. The result is that every subsequent read from disk, from NVMe or from a network storage service, goes straight to I/O and the site's TTFB goes up. If you really need it for testing, just use echo 1, which only frees the page cache, and after the test it refills itself.
A more useful setting is vm.swappiness. The default value on many distributions is 60, which isn't conservative for a web server. On a server with 16 gigabytes of RAM, a value of 10 to 20 is more sensible: the kernel holds off on swap as much as possible and only goes to it when truly necessary. Put this in /etc/sysctl.d/99-swap.conf so it persists after reboot:
vm.swappiness = 10
vm.vfs_cache_pressure = 50
A lower vfs_cache_pressure value makes the kernel release inode and dentry cache later. On a server with thousands of small files, this makes a noticeable difference in I/O load.
Which tool to pick for Linux RAM usage
Three common tools, three different jobs:
| Tool | What it says | When it's useful |
|---|---|---|
free -h | A snapshot, with buff/cache and available broken out | First look, quick diagnosis |
vmstat 1 | Swap exchange rate and I/O queue over a time interval | When you want to know if the problem is acute |
smem -rs rss | Each process's real share, accounting for shared memory | When php-fpm and MySQL share memory and ps misleads you |
If smem isn't installed, ps_mem is a good alternative. Their difference from top is that they don't count shared memory between processes multiple times. On a server with 20 php-fpm workers, this difference can create several gigabytes of error.
The real ceiling, not the imaginary one
A point that's less often mentioned: on a virtual machine, the total number in free isn't always what was sold to you. If the server has 16 gigabytes of RAM but the kernel booted with the mem=14G parameter or the hypervisor's balloon driver has borrowed part of it, total shows less. Before any decision, compare dmidecode -t memory | grep -i size with the output of free. If these two don't match, the problem is configuration, not capacity.
And if after all these checks you conclude that capacity really is short, the right solution is upgrading RAM, not fiddling with swappiness. For WordPress sites running on Linux hosting, this is usually the point where you need to decide.
Frequently asked questions
Why does free say memory is full but the site isn't slow?
Because that memory is actually buff/cache, not real process usage. The Linux kernel keeps files and disk blocks in RAM so the next read is faster, and this memory is freed the moment it's needed. Look at the available column; if it's above 10 percent of total RAM, your server is healthy.
What's the difference between used and available in free's output?
The used column is memory occupied by processes and the kernel that isn't easily freed. The available column is the kernel's estimate of memory that can reach a new process without going to swap, and it includes the reclaimable portion of buff/cache. For decision-making, always base it on available.
How do I know the OOM Killer killed my process?
Run dmesg -T | grep -i "out of memory". If you see a line with the process name and PID, the kernel killed it due to a real memory shortage. This is a definitive sign of RAM shortage and can't be confused with buff/cache. In this case, the /var/log/syslog log or journalctl -k has the same record.
Is clearing buff/cache on a production server safe?
It's safe but not recommended. The command echo 3 > /proc/sys/vm/drop_caches doesn't break anything, but it throws away the cache and temporarily raises disk I/O load, which directly affects the site's response time. If you only need it for testing, echo 1 is enough and the system refills the cache itself.
The next step is clear: put free -h and vmstat 1 5 side by side once and see whether si and so are zero or not. If they're zero, ignore that red free number and go look for something else that's slowing down the site. If they're not zero, find the real consumer with ps aux --sort=-rss and start from there.
Comments 0
No comments yet — be the first!