Computing Total and Free RAM in Linux with Qt

KDE Plasma Activity Manager

It is sometimes useful to measure the amount of free memory while your app is running. I typically do this to ensure there is no memory leak, for example. Even a small amount of leaked memory may be a problem for applications that are supposed to run for long time, without downtime. Instead of writing this each and every time, I added a function to my utils library here.

Computation

Computing “free” memory is not entirely trivial. Memory management is a bit complex. However, this is what I came up with. First, let’s define:

MemTotal ($T$): total usable ram (i.e. physical ram minus a few reserved
bits and the kernel binary code).

MemFree ($F$): the sum of LowFree+HighFree, where lowmem is memory which can be used for everything that highmem can be used for, but it is also available for the kernel’s use for its own data structures. Among many other things, it is where everything from the Slab is allocated. Bad things happen when you’re out of lowmem. Highmem is all memory above ~860MB of physical memory. Highmem areas are for use by userspace programs, or for the pagecache. The kernel must use tricks to access this memory, making it slower to access than lowmem.

Buffers ($B$): relatively temporary storage for raw disk blocks shouldn’t get tremendously large (20MB or so).

Cached ($C$): in-memory cache for files read from the disk (the pagecache). Doesn’t include SwapCached.

SReclaimable ($R$): part of Slab, that might be reclaimed, such as caches.

Slab: in-kernel data structures cache.

https://www.kernel.org/doc/Documentation/filesystems/proc.txt

Data is provided in /proc/meminfo. For example:

> cat /proc/meminfo

MemTotal:     16344972 kB
MemFree:      13634064 kB
MemAvailable: 14836172 kB
Buffers:          3656 kB
Cached:        1195708 kB
SwapCached:          0 kB
Active:         891636 kB
Inactive:      1077224 kB
HighTotal:    15597528 kB
HighFree:     13629632 kB
LowTotal:       747444 kB
LowFree:          4432 kB
SwapTotal:           0 kB
SwapFree:            0 kB
Dirty:             968 kB
Writeback:           0 kB
AnonPages:      861800 kB
Mapped:         280372 kB
Shmem:             644 kB
KReclaimable:   168048 kB
Slab:           284364 kB
SReclaimable:   159856 kB
SUnreclaim:     124508 kB
PageTables:      24448 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
WritebackTmp:        0 kB
CommitLimit:   7669796 kB
Committed_AS:   100056 kB
VmallocTotal:   112216 kB
VmallocUsed:       428 kB
VmallocChunk:   111088 kB
Percpu:          62080 kB
HardwareCorrupted:   0 kB
AnonHugePages:   49152 kB
ShmemHugePages:      0 kB
ShmemPmdMapped:      0 kB

By reading kernel sources, it seems kB is the only unit allowed in the file and kB is intended as kibibytes: https://github.com/torvalds/linux/blob/v6.7/fs/proc/meminfo.c#L28.

Total usable memory, part of which is clearly already used, is simply $T$. Computing available memory ($A$), instead, is a bit more convoluted. By “available memory”, I mean unused or, however, allocatable. According to most sources, this is how it can be computed, in bytes, as:

$$A=\frac{(F+B+C+R)}{1024}$$

This is what htop does. free is implemented like this instead.

How to Use

Simply run the function and read the result:

#include <lqtutils_system.h>

std::optional<lqt::MemData> mem = lqt::read_mem_data();
if (mem) {
    qInfo() << "Total:" << QLocale::system().formattedDataSize(mem->totalMemBytes);
    qInfo() << "Free :" << QLocale::system().formattedDataSize(mem->freeMemBytes);
}

Have fun! 😉

Leave a Reply

Your email address will not be published. Required fields are marked *