What Ate My RAM? Searching for Memory Use on GNU/Linux systems
One of the most common GNU/Linux topics that users ask about is memory use. There are many guides, but most of the guides written by experienced systems engineers focus on performance, and it’s hard to find a comprehensive guide to the simple question, “what is using memory in this system?”
The standard tools: free and top
The most common process accounting tools are provided by procps. These will be available by default on nearly all Linux systems.
free will give you a quick summary of the system, overall. I’ll use
the -h option here (but sometimes it’s easier to spot outliers when
numbers aren’t converted to human readable units):
$ free -h
total used free shared buff/cache available
Mem: 15Gi 9.0Gi 2.8Gi 3.5Gi 6.5Gi 6.4Gi
Swap: 8.0Gi 2.8Gi 5.2Gi
In this example, the host has approximately 16 GiB of RAM, and is configured for 8 GiB of swap on zram.
“Available” is a value provided by the Linux kernel which estimates the amount of memory that could be given to applications without causing the kernel to start searching for memory pages to reclaim or swap, and the “used” value is the “total” minus “available” memory.
A relatively small portion of the page cache (where Linux caches files) will present as “used” memory. In some cases, especially if you have a large amount of memory and a lot of it is currently used for page cache, the amount of memory that appears to be “used” might be larger than you expect. I’ll discuss that later.
top can also give you a summary of the state of the system, but adds
detail about individual processes.
Tasks: 379 total, 1 running, 378 sleep, 0 d-sleep, 0 stopped, 0 zombie
%Cpu(s): 1.3 us, 0.8 sy, 0.0 ni, 97.3 id, 0.0 wa, 0.3 hi, 0.3 si, 0.0 st
MiB Mem : 15687.4 total, 2534.7 free, 9103.6 used, 6748.9 buff/cache
MiB Swap: 8192.0 total, 5370.1 free, 2821.9 used. 6583.7 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5814 gordon 20 0 13.2g 1.1g 307780 S 2.1 7.0 214:53.65 firefox
605677 gordon 20 0 3431312 665044 130088 S 0.0 4.1 0:43.69 Isolated Web Co
6144 gordon 20 0 3780996 649408 117208 S 0.0 4.0 18:30.94 WebExtensions
4998 gordon 20 0 4438168 608468 194156 S 0.0 3.8 16:09.63 thunderbird
Here we see information about memory use that’s similar to the
information provided by free, but we also see a description of how
much time CPUs spend in various states and information about specific
processes. The resident size (RES) of a process provides information
about how much memory a program is using, but it can be misleading,
because memory can be shared among multiple processes.
top can also display information about how much of a process’ memory
is in swap, but this is not in the default set of columns. If you want
to identify processes using swap space, press the f key to open the
field manager, use the arrow keys to select the SWAP field, then
press the d key (and s if you want to sort based on that field),
and finally q to return to the process list.
Making sense of processes sharing memory: smem
The smem tool is not part of procps and
users will probably need to install it. In addition to the information
that the standard tools can provide, smem adds a “proportional” size
field that represents the memory that is unique to one process plus a
fraction of its shared memory, divided among the processes sharing
that memory segment.
Adding the resident size of several processes may over-estimate their memory use when they share memory segments, but adding their “proportional” size will not.
$ smem -s pss -r | head
PID User Command Swap USS PSS RSS
5814 gordon /usr/lib64/firefox/firefox 203036 839880 932231 1174208
6144 gordon /usr/lib64/firefox/firefox 69852 566560 571748 688328
605677 gordon /usr/lib64/firefox/firefox 3868 530256 537617 664648
4998 gordon /usr/lib64/thunderbird/thun 184692 462264 510504 621840
561266 gordon /usr/lib64/firefox/firefox 126240 398612 406060 531920
606913 gordon /usr/lib64/firefox/firefox 3796 324420 331144 456280
5985 gordon /usr/lib64/firefox/firefox 13864 322400 330093 449216
571137 gordon /usr/lib64/firefox/firefox 20856 295132 301865 426320
23559 gordon /usr/lib64/firefox/firefox 110424 275128 280471 405600
Examining kernel memory use: slabtop
slabtop is another tool provided by procps-ng. It provides a sorted
list, like top, but this list represents different data types
allocated in the kernel. Run sudo slabtop --human, and press the c
key to sort by the size of each cache.
Active / Total Objects (% used) : 2267240 / 2936377 (77.2%)
Active / Total Slabs (% used) : 59549 / 59549 (100.0%)
Active / Total Caches (% used) : 438 / 535 (81.9%)
Active / Total Size (% used) : 386Mi / 502Mi (77.0%)
Minimum / Average / Maximum Object : 0.01K / 0.17K / 12.50K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
88118 66583 75% 0.93K 2717 34 84Mi btrfs_inode
149191 97228 65% 0.57K 5347 28 83Mi radix_tree_node
1975 1925 97% 12.50K 988 2 30Mi task_struct
146076 97308 66% 0.19K 6956 21 27Mi dentry
In this example, we can see that 84 MiB have been allocated to store btrfs inodes, and 27 MiB have been allocated to store directory entries.
When these values are small, users can usually ignore the specific meanings of each data type. But if something is very large, users can look up how that type is used and whether the size of that cache should be investigated further.
Disk and filesystem cache
Disk and network storage is very slow, relative to a CPU and RAM. Memory that isn’t used for anything more important will be used by the kernel to improve the efficiency of reading and writing to slow storage. The vast majority of this memory is just a copy of information that’s on those devices, so when an application requests a memory allocation, the kernel can simply drop some of that cached memory.
But remember that the “available” memory value is an estimate. The kernel will start searching for pages to swap out before it drops 100% of the filesystem cache. Some of this memory affects the “used” value.
The process of calculating the amount of page cache that is treated as “used” memory is complex, as seen here. You can use the used-page-cache script to estimate how much of your system’s “used” memory is actually cache which the kernel may be able to free without necessarily pushing pages into swap.
You can also tune the kernel to protect less memory from reclamation. This will generally make performance worse later if you use enough memory to cause the system to start swapping, but if you’re trying to observe the amount of memory that is being used for something other than cache, you can do it anyway.
echo 8448 | sudo tee /proc/sys/vm/min_free_kbytes
Furthermore, you can instruct the kernel to immediately drop most cache memory, which may make it easier to get a simple value that represents the amount of memory used overall for things other than cache.
$ grep SReclaim /proc/meminfo ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; grep SReclaim /proc/meminfo
SReclaimable: 272620 kB
3
SReclaimable: 67088 kB
Files stored in RAM
Many Linux systems will use “tmpfs” to create directories that store
files in RAM. If you copy files to those directories, free will
report more memory used. Use df to examine the amount of space
“used” by tmpfs filesystems.
$ df -t tmpfs
Filesystem 1K-blocks Used Available Use% Mounted on
tmpfs 8031932 92 8031840 1% /dev/shm
tmpfs 3212776 3044 3209732 1% /run
none 1024 0 1024 0% /run/credentials/systemd-journald.service
none 1024 0 1024 0% /run/credentials/systemd-resolved.service
tmpfs 8031932 3924 8028008 1% /tmp
tmpfs 1606384 368 1606016 1% /run/user/556600005
ZRAM
zram is a kernel feature that creates a storage device in RAM. Some
systems use this device instead of swap in order to compress memory
without swapping to disk. On a system that swaps to disk, memory in
swap is not “used”, but on a system that uses swap on zram, the
compressed data is still “used” RAM.
Use zramctl to get information about memory used by zram devices.
$ zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 lzo-rle 8G 2.4G 707.4M 725M [SWAP]
ZFS
ZFS is a filesystem developed by the
OpenZFS project. It is not part
of the standard Linux kernel because it uses the CDDL license, which
is not compatible with the GPL 2.0 license.
One of the unusual behaviors of ZFS is that its filesystem cache (ARC)
appears to be “used” memory in the output of free rather than in the
buff/cache column like other filesystems.
Use the arcstat tool to get information about memory “used” by ZFS:
$ arcstat
time read ddread ddh% dmread dmh% pread ph% size c avail
11:58:00 9 0 0 9 100 0 0 125G 126G 52.3G
HugePages
The Linux kernel supports a feature named “HugePages” that allows processes to reserve large blocks of memory, as well as allocating blocks larger than the standard 4k page size.
When memory is reserved for HugePages, it will appear as “used” memory, even when the software that reserved the memory isn’t running.
If you can’t find memory used anywhere else, look for memory that might be reserved for HugePages:
$ grep Huge /proc/meminfo
AnonHugePages: 0 kB
ShmemHugePages: 352256 kB
FileHugePages: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
References:
1: https://kernel-internals.org/mm/understanding-proc-meminfo/ 2: https://blog.thalheim.io/2025/10/17/zfs-ate-my-ram-understanding-the-arc-cache/