Understanding the Linux free Command, Buffers/Cache and Their Reclamation
This article explains how the Linux free command reports memory usage, clarifies the roles of buffer cache and page cache, demonstrates which cache memory can be reclaimed, and shows practical tests using tmpfs, shared memory, and mmap with code examples.
Understanding the Linux free Command, Buffers/Cache and Their Reclamation
In Linux systems the free command is commonly used to view memory usage. On a RHEL6 machine the default output shows values in kilobytes, which can be confusing on servers with large RAM (e.g., 128 GB).
People generally fall into three levels of understanding:
Unaware – they see large numbers and think Linux is using too much memory.
Superficially aware – they notice that buffers/cache occupy a lot of memory and assume it can be treated as free.
Truly aware – they know that the numbers alone do not tell whether the memory is actually available for applications.
Most readers are at the second level, believing that buffers and cached memory can be reclaimed when memory pressure rises. The article investigates whether this assumption is correct.
What are buffer and cache?
In Linux memory management, buffer cache refers to the cache for block‑device I/O, while page cache is the cache for file data pages. Historically buffers were write‑back caches for block devices and caches were read‑caches, but modern kernels use both for different purposes.
Page cache stores file data that has been read or written, and it can be mapped into a process via mmap . Buffer cache handles block‑device writes and is used when the kernel writes back dirty pages.
How is cache reclaimed?
When the system runs low on memory the kernel attempts to free memory, primarily by dropping page cache and reclaiming slab objects. This can be triggered manually by writing to /proc/sys/vm/drop_caches :
echo 1 > /proc/sys/vm/drop_caches – drop page cache only.
echo 2 > /proc/sys/vm/drop_caches – drop dentries and inode caches.
echo 3 > /proc/sys/vm/drop_caches – drop both page cache and slab caches.
Clearing cache incurs I/O cost because dirty pages must be written back to storage before they can be freed.
Cache that cannot be reclaimed
Not all cached memory can be freed. The article presents three examples.
tmpfs
Files stored in a tmpfs filesystem reside in page cache. Creating a 13 GB file in /tmp/tmpfs increases the cached column by 13 GB, and the memory remains allocated even after running drop_caches until the file is deleted.
Shared memory (shm)
A small C program creates a ~2 GB System V shared memory segment, writes to it, and exits without removing the segment. The cached memory grows and stays unreclaimed until the segment is removed with shmctl(..., IPC_RMID) or ipcrm . The program source is:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define MEMSIZE 2048*1024*1023
int main() {
int shmid;
char *ptr;
pid_t pid;
struct shmid_ds buf;
int ret;
shmid = shmget(IPC_PRIVATE, MEMSIZE, 0600);
if (shmid < 0) { perror("shmget()"); exit(1); }
ret = shmctl(shmid, IPC_STAT, &buf);
if (ret < 0) { perror("shmctl()"); exit(1); }
printf("shmid: %d\n", shmid);
printf("shmsize: %d\n", buf.shm_segsz);
buf.shm_segsz *= 2;
shmctl(shmid, IPC_SET, &buf);
shmctl(shmid, IPC_SET, &buf);
pid = fork();
if (pid < 0) { perror("fork()"); exit(1); }
if (pid == 0) {
ptr = shmat(shmid, NULL, 0);
if (ptr == (void*)-1) { perror("shmat()"); exit(1); }
bzero(ptr, MEMSIZE);
strcpy(ptr, "Hello!");
exit(0);
} else {
wait(NULL);
ptr = shmat(shmid, NULL, 0);
if (ptr == (void*)-1) { perror("shmat()"); exit(1); }
puts(ptr);
exit(0);
}
}mmap with MAP_SHARED
Another program creates a 2 GB file, maps it with MAP_SHARED|MAP_ANON , zero‑fills it, sleeps for 100 seconds, then unmaps. While the process runs, the cached column grows by 2 GB and cannot be reclaimed until munmap finishes. The source code is:
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#define MEMSIZE 1024*1024*1023*2
#define MPFILE "./mmapfile"
int main() {
void *ptr;
int fd;
fd = open(MPFILE, O_RDWR);
if (fd < 0) { perror("open()"); exit(1); }
ptr = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, fd, 0);
if (ptr == NULL) { perror("malloc()"); exit(1); }
printf("%p\n", ptr);
bzero(ptr, MEMSIZE);
sleep(100);
munmap(ptr, MEMSIZE);
close(fd);
exit(1);
}These experiments show that cache used by tmpfs files, System V shared memory, and MAP_SHARED mmap regions remains occupied until the underlying objects are explicitly removed.
Key Takeaways
Reclaiming file cache generates additional I/O because dirty pages must be written back.
Files stored in tmpfs keep their cache until the files are deleted.
System V shared memory segments keep their cache until they are removed with shmctl or ipcrm .
MAP_SHARED mmap regions keep their cache until the mapping is unmapped.
Both shm and MAP_SHARED mmap are implemented on top of tmpfs, so they share the same cache‑retention behavior.
Understanding these details helps you interpret the output of free more accurately and avoid the misconception that all buffer/cache memory is instantly reusable.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.