What Do “buffers” and “cached” Really Mean in Linux’s free Command?
This article demystifies the Linux free command’s “buffers” and “cached” fields by tracing their origins through /proc/meminfo, kernel source functions such as meminfo_proc_show, nr_blockdev_pages, and page‑cache mechanisms, and demonstrates the differences with practical experiments.
The free command is the most common tool on Linux for viewing memory usage, but few can clearly explain the difference between “buffers” and “cached”.
We start with the conclusion; the detailed analysis follows for those interested
buffersrepresents cache pages occupied by block devices, including direct reads/writes to block devices and filesystem metadata ( (metadata)) such as the SuperBlock cache pages. cached represents cache pages occupied by ordinary file data.
Analysis process
First we use strace to trace the free command and see how it calculates buffers and cached:
# strace free
...
open('/proc/meminfo', O_RDONLY) = 3
lseek(3, 0, SEEK_SET) = 0
read(3, 'MemTotal: 3848656 kB
MemF'..., 2047) = 1170
...Obviously free reads information from /proc/meminfo, which yields the same result as directly catting the file:
# cat /proc/meminfo
MemTotal: 3848656 kB
MemFree: 865640 kB
Buffers: 324432 kB
Cached: 2024904 kB
...
SwapTotal: 2031612 kB
SwapFree: 2031612 kB
...
Shmem: 5312 kB
...The values Buffers and Cached in /proc/meminfo are derived from kernel source fs/proc/meminfo.c, specifically the function meminfo_proc_show(). The Cached value is calculated by the formula:
global_page_state(NR_FILE_PAGES) – total_swapcache_pages – i.bufferram global_page_state(NR_FILE_PAGES)counts all page‑cache pages, which include:
Cached Buffers(the i.bufferram term above), coming from nr_blockdev_pages() swap cache pages
The global_page_state(NR_FILE_PAGES) value can be seen in /proc/vmstat as nr_file_pages, measured in pages (1 page = 4 KB), while free reports in kilobytes.
Updating the number of block‑device cache pages ( nrpages) is done by kernel functions such as __inc_zone_page_state(page, NR_FILE_PAGES) and __dec_zone_page_state(page, NR_FILE_PAGES).
What is Swap Cache?
User‑process memory pages are of two kinds: file‑backed pages (associated with files) and anonymous pages (not associated with any file, e.g., memory allocated via malloc()). When an anonymous page is swapped out, it has no file to write back to, so it is stored in a swap device, forming the swap cache. The swap cache functions like a page cache for swap devices, using a radix‑tree, and is managed by the kernel similarly to the file page cache.
Only anonymous pages that are about to be swapped out or have been swapped in remain in the swap cache until they are modified or the swap space is reclaimed.
cached
Cacheddenotes the number of ordinary file cache pages, i.e., the total of global_page_state(NR_FILE_PAGES) minus total_swapcache_pages and i.bufferram.
buffers
From the source we see that buffers comes from the return value of nr_blockdev_pages():
long nr_blockdev_pages(void)
{
struct block_device *bdev;
long ret = 0;
spin_lock(&bdev_lock);
list_for_each_entry(bdev, &all_bdevs, bd_list) {
ret += bdev->bd_inode->i_mapping->nrpages;
}
spin_unlock(&bdev_lock);
return ret;
}This code iterates over all block devices, summing the number of pages in each device’s inode mapping, which yields the buffers count. The block‑device mapping is updated by generic functions add_to_page_cache and delete_from_page_cache:
static inline int add_to_page_cache(struct page *page,
struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask)
{
int error;
__set_page_locked(page);
error = add_to_page_cache_locked(page, mapping, offset, gfp_mask);
if (unlikely(error))
__clear_page_locked(page);
return error;
}
void delete_from_page_cache(struct page *page)
{
struct address_space *mapping = page->mapping;
void (*freepage)(struct page *);
BUG_ON(!PageLocked(page));
freepage = mapping->a_ops->freepage;
spin_lock_irq(&mapping->tree_lock);
__delete_from_page_cache(page, NULL);
spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_cache_page(page);
if (freepage)
freepage(page);
page_cache_release(page);
}When the mapping corresponds to a block device, the statistics affect buffers; when it corresponds to a regular file inode, they affect cached.
Block devices are opened via bdev->bd_inode->i_mapping, and filesystem superblocks also use block devices, so their metadata (e.g., SuperBlock) contributes to buffers.
static int blkdev_open(struct inode *inode, struct file *filp)
{
struct block_device *bdev;
filp->f_flags |= O_LARGEFILE;
if (filp->f_flags & O_NDELAY)
filp->f_mode |= FMODE_NDELAY;
if (filp->f_flags & O_EXCL)
filp->f_mode |= FMODE_EXCL;
if ((filp->f_flags & O_ACCMODE) == 3)
filp->f_mode |= FMODE_WRITE_IOCTL;
bdev = bd_acquire(inode);
if (bdev == NULL)
return -ENOMEM;
filp->f_mapping = bdev->bd_inode->i_mapping;
return blkdev_get(bdev, filp->f_mode, filp);
} struct super_block {
...
struct block_device *s_bdev;
...
}
int inode_init_always(struct super_block *sb, struct inode *inode)
{
if (sb->s_bdev) {
struct backing_dev_info *bdi;
bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
mapping->backing_dev_info = bdi;
}
...
}Thus buffers represents cache pages used by block devices, including direct I/O and filesystem metadata such as SuperBlock.
Verification
We performed tests to verify the conclusions. Scanning the filesystem with find increased the buffers count:
# free
total used free shared buffers cached
Mem: 3848656 2889508 959148 5316 263896 2023340
-/+ buffers/cache: 602272 3246384
Swap: 2031612 0 2031612
# find / -name abc.def
# free
total used free shared buffers cached
Mem: 3848656 2984052 864604 5320 319612 2023348
-/+ buffers/cache: 641092 3207564
Swap: 2031612 0 2031612Reading a block device directly also increased buffers:
# free
total used free shared buffers cached
Mem: 3848656 3006944 841712 5316 331020 2028648
-/+ buffers/cache: 647276 3201380
Swap: 2031612 0 2031612
# dd if=/dev/sda1 of=/dev/null count=2000
2000+0 records in
2000+0 records out
1024000 bytes (1.0 MB) copied, 0.026413 s, 38.8 MB/s
# free
total used free shared buffers cached
Mem: 3848656 3007704 840952 5316 331872 2028692
-/+ buffers/cache: 647140 3201516
Swap: 2031612 0 2031612Conclusion
The free command’s buffers field shows cache pages occupied by block devices, including direct block I/O and filesystem metadata (e.g., SuperBlock). The cached field shows cache pages occupied by ordinary files.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Linux
Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.
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.
