39.6 Page Cache and Buffer Cache: How Linux Uses RAM Aggressively
Right, let’s talk about your RAM. Or, more accurately, let’s talk about how Linux has already laid claim to most of your RAM the second it finished booting. If you run free -h and see a paltry amount of “free” memory and start panicking, relax. You’re not about to crash. You’re witnessing one of Linux’s best performance tricks: using every spare byte of RAM it can get its hands on as a massive, intelligent cache. It’s not being greedy; it’s being brilliantly pragmatic.
The core idea is simple: reading from RAM is about 100,000 times faster than reading from even the fastest SSD. So, if there’s data that might be needed again, why on earth would we leave it on the slow disk when we have all this beautiful, empty, expensive RAM sitting around? We wouldn’t. And Linux doesn’t.
This aggressive caching is primarily handled by two old friends who are often confused: the Page Cache and the Buffer Cache.
The Page Cache: It’s Mostly This
When we talk about Linux caching, about 95% of the time we’re talking about the Page Cache. This is the big one. Its job is to cache pages of data from your files. Every time you read() from a file on disk, the kernel checks the Page Cache first. If the data is already in RAM (a cache hit), it returns it instantly, avoiding a painful trip to the storage I/O dungeon. If it’s not there (a cache miss), it reads it from disk, and it stashes a copy in the Page Cache on the way through, just in case you’re back for more.
Think of it as your system’s working memory for files. That massive application you just launched? Its binary and libraries were read from disk and are now cached in RAM, so the next launch will be lightning fast. That multi-gigabyte dataset you’re analyzing? Chunks of it are living happily in the Page Cache as you work on it.
You can see this in action. Let’s create a tiny file and then watch the kernel eagerly cache it.
# Create a 100MB file
dd if=/dev/zero of=testfile bs=1M count=100
# Now, read from it
cat testfile > /dev/null
# Check the cache stats. Look for the 'cached' value.
free -h
You’ll see your cached memory value jump up by roughly 100MB. That’s your file, now living rent-free in the Page Cache. The kernel will keep it there until it needs the RAM for something else.
The Buffer Cache: A Quaint Relic (Mostly)
Ah, the Buffer Cache. This one causes so much confusion. Historically, the Buffer Cache was for caching filesystem metadata (inodes, directory blocks) and raw block device I/O, bypassing the filesystem layer entirely.
Here’s the crucial part: in modern kernels (roughly 2.4 and later), the Buffer Cache isn’t really a separate cache anymore. It’s an extension of the Page Cache. The same physical pages of RAM are used for both. The distinction now is mostly a accounting one. The “Buffers” entry in free represents pages that are being used for raw block device access or for filesystem metadata.
For you, the practical takeaway is this: Stop worrying about the difference. The Page Cache is the unified, primary mechanism. The Buffer Cache value is usually small and is included in the overall “cached” total for all practical purposes. If it’s large, it might indicate a lot of direct disk I/O or a massive filesystem with tons of metadata being accessed.
How The Kernel Decides What to Evict
You’ve got 16GB of RAM. The Page Cache grows to 15GB. You open a new app that needs 2GB. What happens? Does the system grind to a halt while it writes 2GB of cache back to disk? Absolutely not.
The kernel uses sophisticated algorithms (primarily Least Recently Used - LRU) to find pages that haven’t been touched in a while. These “cold” pages are perfect candidates for eviction. If the page is clean (it’s an exact copy of what’s on disk), the kernel can simply discard it—poof, 4KB of RAM freed instantly. If the page is dirty (it’s been written to and is newer than the disk copy), it gets scheduled to be written back to disk, and then its RAM is freed.
This is why your system can feel snappy even when “free” memory is near zero. The kernel is constantly shuffling these pages behind the scenes, keeping the “hot” (frequently used) data in RAM and jettisoning the “cold” data with ruthless efficiency. It’s a brilliant, continuous triage system.
The Pitfalls: When Aggressive Caching Bites Back
This isn’t all sunshine and rainbows. The design has a dark side, and it’s called I/O spikes.
Imagine a long-running process that has built up a massive Page Cache—say, 20GB on a 24GB machine. Now, a different memory-hungry application starts up and demands 10GB. The kernel must rapidly evict 10GB of cached pages to make room. If a significant portion of those pages are dirty (from writes that haven’t been flushed to disk yet), the kernel now has to synchronously write all that data to disk right now.
This can cause massive, intermittent disk I/O stalls. Your system, which was feeling fine a second ago, suddenly becomes unresponsive. The cat command you typed hangs for 30 seconds. Your music skips. It’s a classic “why is my fast Linux machine suddenly so slow?” moment.
You can see the current state of dirty pages:
cat /proc/meminfo | grep Dirty
The kernel has tunable parameters (/proc/sys/vm/dirty_ratio, dirty_background_ratio, etc.) to control how much dirty data can be in memory and how aggressively it’s written back. Tuning these is a dark art, but if you’re running a write-heavy database or virtual machine, you might need to dive in to smooth out these I/O cliffs.
The best practice? Understand that “free” memory is wasted memory. Don’t panic. Monitor your cached value and your dirty pages. And if you ever need to truly benchmark disk read speed and want to bypass the cache entirely, use dd with the oflag=direct flag. Otherwise, just lean back and let the kernel do its thing. It’s probably smarter than both of us about this.