How do you tell the difference between an actual memory leak and normal Linux page cache growth when "free -h" shows memory almost fully used?
Quick Answer
Look at the `available` column (not `free`) in `free -h`, which already accounts for reclaimable cache — if `available` stays healthy while `used` climbs, that is mostly page cache, not a leak. Confirm by watching a specific process's RSS/heap over time rather than system-wide "used" memory.
Detailed Answer
Linux aggressively uses spare RAM for page cache (file-backed pages) and buffers, on the principle that unused memory is wasted memory — that cache is reclaimed automatically the instant an application needs it. This means free -h showing very little in the free column is normal and expected on a healthy, long-running Linux box; the column that matters is available, which is the kernel's own estimate of memory that can be given to a new allocation without swapping, already accounting for reclaimable cache and buffers. If available stays roughly stable over days while used grows, you are looking at cache growth, not a leak.
To confirm a real leak, stop looking at system-wide memory and track a specific process: use ps -o rss,vsz -p <pid> or pidstat -r -p <pid> 60 sampled over hours, and watch whether RSS grows monotonically with no corresponding drop after garbage collection (for managed runtimes) or after requests complete. smem or /proc/<pid>/smaps_rollup can break down how much of a process's RSS is private (its own leaked memory) versus shared (mapped libraries, shared cache) — a real leak shows up as private, dirty memory (Private_Dirty) climbing continuously. Also check /proc/meminfo for Slab and SReclaimable vs SUnreclaim — a leak in kernel-level allocations (e.g., a buggy driver or a container leaking dentries/inodes) shows up as SUnreclaim growing rather than in any single process's RSS at all.
Code Example
# The column that actually matters free -h # look at "available", not "free" # Track a specific process's RSS over time (not system-wide "used") pidstat -r -p <pid> 60 # Break down private (leak-relevant) vs shared memory for a process grep -E "Private_Dirty|Shared" /proc/<pid>/smaps_rollup # Distinguish reclaimable kernel slab (safe) from unreclaimable (potential leak) grep -E "^Slab|SReclaimable|SUnreclaim" /proc/meminfo # Force a cache drop ONLY to confirm your hypothesis in a non-prod box # (never routinely run this in production — it just evicts useful cache) sync; echo 1 > /proc/sys/vm/drop_caches
Interview Tip
Anchor on the "available" vs "free" distinction — it is the single most common Linux memory misreading, and calling it out explicitly signals real operational experience.