Fundamentals 12 min read

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.

Open Source Linux
Open Source Linux
Open Source Linux
What Do “buffers” and “cached” Really Mean in Linux’s free Command?

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

buffers

represents 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

Cached

denotes 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   2031612

Reading 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   2031612

Conclusion

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

memory-managementKernelLinuxfree commandBufferscached
Open Source Linux
Written by

Open Source Linux

Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.