For a few months now I've been rebuffed, being told “there's no single answer” when asking for a way to calculate the “really used memory” on my GNU/Linux system.
Obviously `free` wasn't giving what I wanted, since I was reaching OOM conditions when it said I was using 14% of my RAM (hint: big tmpfs). Of course, that's if you look at the “±buffers/cache” line. If however you look at the first line, it seems you're always almost out of memory! (hint: disk cache)
Not very satisfying, but today I finally got it right.
Thanks to Munin's memory graphs, which helped me make sense of some variables in /proc/meminfo, so that I knew how to count the used RAM.
On my machine, imagine that Shmem is a few centimeters higher. So it looks a bit more like this:
Turns out it's the free RAM that's easy to count, so the answer is:
Used RAM = MemTotal - (MemFree+Buffers+SReclaimable+Cached-Shmem)
Here's a shell script that does correctly what `free` does wrong:
#!/bin/sh
div=1
unit=K
[ "${1}" = '-m' ] && unit=M && div=1024
[ "${1}" = '-g' ] && unit=G && div=$((1024*1024))
eval "$(sed 's/^\([^:]*\):[[:space:]]*\([0-9]*\).*$/\1=\2/;s/(//;s/)//' /proc/meminfo)"
echo "total $((MemTotal/div))${unit} used $(( ( MemTotal - (MemFree+Buffers+SReclaimable+Cached-Shmem) ) / div ))${unit}"
Implementation in C is here
And here's a conky patch:
--- conky-1.9.0/src/linux.c.old 2014-06-18 11:05:42.965999512 +0200
+++ conky-1.9.0/src/linux.c 2014-06-18 23:57:32.601326864 +0200
@@ -159,7 +159,8 @@
FILE *meminfo_fp;
static int rep = 0;
- /* unsigned int a; */
+ unsigned long long shmem, sreclaimable;
+
char buf[256];
info.mem = info.memmax = info.swap = info.swapfree = info.swapmax = info.bufmem =
@@ -186,6 +187,11 @@
sscanf(buf, "%*s %llu", &info.buffers);
} else if (strncmp(buf, "Cached:", 7) == 0) {
sscanf(buf, "%*s %llu", &info.cached);
+
+ } else if (strncmp(buf, "Shmem:", 6) == 0) {
+ sscanf(buf, "%*s %llu", &shmem);
+ } else if (strncmp(buf, "SReclaimable:", 13) == 0) {
+ sscanf(buf, "%*s %llu", &sreclaimable);
}
}
@@ -193,7 +199,16 @@
info.memeasyfree = info.memfree;
info.swap = info.swapmax - info.swapfree;
- info.bufmem = info.cached + info.buffers;
+ /* Reclaimable memory: does not include shared memory, which is part of cached but unreclaimable.
+ Includes the reclaimable part of the Slab cache though.
+ Note: when shared memory is swapped out, shmem decreases and swapfree decreases - we want this.
+ */
+ info.bufmem = (info.cached - shmem) + info.buffers + sreclaimable;
+
+ /* Now (info.mem - info.bufmem) is the *really used* (aka unreclaimable) memory.
+ When this value reaches the size of the physical RAM, and swap is full or non-present, OOM happens.
+ Therefore this is the value that the user wants to monitor, regarding their RAM.
+ */
fclose(meminfo_fp);
return 0;
Edit: reported, pull-requested, merged.
Here we go! I don't know if a patch for `free` would be envisionable, but probably for such a system tool it wouldn't make sense.
For those wondering: this post is in English because I wanted English-speaking developers and users to be able to read it.