Linux / Bash

Linux Memory Leak Analysis: free -m High "Used" Memory vs Cached/Buffers

· by DebuggedIt

Quick answer

High "used" memory reported by free -m is very often not a leak at all — Linux deliberately uses available RAM for disk caching and buffers to improve...

High "used" memory reported by free -m is very often not a leak at all — Linux deliberately uses available RAM for disk caching and buffers to improve performance, and this cached memory is immediately reclaimable whenever an application actually needs it, which is fundamentally different from memory a leaking process has genuinely locked away and made unavailable.

The Problem

Checking memory usage shows what looks like alarmingly high consumption:

free -m
              total        used        free      shared  buff/cache   available
Mem:          16000       14200         300         200        1500       1600

14GB "used" out of 16GB total looks concerning at first glance, especially if no specific application seems to be consuming anywhere near that much memory when checked individually.

What "used" actually contains Genuinely used by processes buff/cache reclaimable instantly if needed

Why It Happens

Linux operates on the principle that unused RAM is wasted RAM — rather than leaving free memory genuinely idle, the kernel uses it to cache recently accessed disk data (page cache) and hold filesystem metadata buffers, since this cached data can dramatically speed up subsequent access to the same files without needing a slower disk read. Critically, this cached memory is not locked away the way memory held by an actual leaking process is — it's immediately, automatically released back to the system the moment any application actually needs that RAM for genuine allocation. This means free -m's raw "used" column, taken in isolation, significantly overstates how much memory is actually unavailable for new use.

The Fix — Reading the Output Correctly

Focus on the available column specifically, not the raw used column, when assessing genuine memory pressure — available is a more accurate, kernel-calculated estimate of memory that could actually be provided to a new application right now, accounting for the fact that cache and buffers can be reclaimed instantly:

free -m
              total        used        free      shared  buff/cache   available
Mem:          16000       14200         300         200        1500       1600

In this example, despite "used" showing 14.2GB, available shows 1.6GB genuinely available for new allocations — this is the number that actually matters for assessing whether the system is under real memory pressure, not the raw "used" figure, which includes a large amount of easily-reclaimable cache.

To distinguish genuine, growing process memory usage (a potential leak) from normal cache accumulation, monitor memory usage over time specifically at the process level, looking for a process whose own memory footprint keeps growing without bound, rather than relying on the system-wide "used" figure alone:

watch -n 5 'ps aux --sort=-%mem | head -10'

A genuine memory leak shows a specific process's own RSS (resident set size) memory usage climbing steadily over time, with no plateau, correlating with that process's own ongoing activity — this is a meaningfully different pattern from overall system "used" memory simply reflecting normal, healthy disk cache accumulation as the system has been running and accessing files.

For a more detailed breakdown of exactly what's consuming memory, /proc/meminfo provides finer-grained detail than free's summary view:

cat /proc/meminfo | head -20

Look specifically at Cached, Buffers, and MemAvailable here for the same underlying distinction free presents in summarized form, useful when you want more granular visibility than the standard free command's summary view provides.

Recognizing a Genuine Leak

A genuine memory leak typically shows: a specific process's own memory usage (checked via ps or top, focused on that specific process, not system-wide totals) growing continuously over time without ever plateauing or decreasing, even during periods when that process should logically be idle or between distinct units of work; the system's available memory correspondingly and genuinely decreasing over the same period, not just the raw "used" figure; and, eventually, if left unaddressed, the OOM killer terminating processes once genuinely available memory is exhausted, which is the eventual real-world consequence a true leak produces that normal cache accumulation alone never does, since cache is always reclaimed automatically before that point is ever reached.

Still Not Working?

If you've confirmed available memory is genuinely low and shrinking over time, and a specific process's own memory usage is confirmed to be growing without bound, proceed to application-level memory profiling tools specific to that process's runtime (like Valgrind for C/C++, a heap profiler for Node.js or Python, or your specific language's own memory analysis tooling) to identify exactly what within that specific process is accumulating and never being released — system-level tools like free and ps can confirm that a leak exists and roughly how severe it is, but pinpointing its exact cause within the application's own code requires tools designed specifically for that purpose.