...

Understanding the Linux Page Cache: Improved Performance Through Caching

Linux Page I see the cache as a direct way to speed up file access, since it handles repeated reads from RAM instead of from slower storage. I’ll show you specifically how the kernel uses this to reduce latency, accelerate workloads such as web servers, databases, and WordPress, and how I can leverage this effect using simple methods.

Key points

The following key points help me to Page Cache to assess and make targeted use of.

  • RAM Cache: File data is stored in memory, reducing access times.
  • Write-back: Write operations are grouped more efficiently as „dirty pages.“.
  • Transparency: Applications benefit without any code changes.
  • Dynamics: The cache frees up memory as needed.
  • Workloads: Web, DB, CI/CD, and logs are seeing noticeable gains.

What is the Linux page cache?

I understand the Page Cache as a memory area in RAM where the kernel stores file blocks as soon as processes use read(), write() or mmap() access files. Each time a file is accessed, the kernel first checks the cache and immediately delivers data from memory if it is already present, which measurably reduces response time. If the data is not found in the cache, the kernel loads it from the storage device, stores it there, and makes it available to the process, resulting in a fast hit the next time it is accessed. This mechanism is closely linked to the Virtual File System and operates transparently to applications, making it universally applicable. This mode of operation leads to a simple principle: I use free RAM as Cache Area instead of letting it go to waste.

Why the Page Cache Noticeably Speeds Things Up

The biggest effect comes from the fact that I Disk I/O drastically reduces latency once recurring data is cached and no longer needs to be read from the storage device. Read operations are then served from RAM, which significantly reduces latency and controller queues. Write operations also benefit because the kernel marks changes as „dirty pages,“ bundles them over time, and later writes them efficiently to the storage medium. This eliminates many small individual accesses that would otherwise strain the storage system, in favor of fewer, larger operations. Overall, after a short warm-up phase, a system feels faster because more working data is in the Memory remain.

Reading, Writing, Dirty Pages: Here's How It Works

A read operation always begins with a cache check, which means I get hits with no wait time and misses cost only once. When writing, the modified content is first stored in RAM and is marked as „dirty,“ remaining in a waiting state until the kernel transfers it to the storage device in batches. If desired, I can force permanent storage with fsync(), which remains important when data Consistency need immediately. This write-back path improves the efficiency of applications that handle many small files, such as PHP code, configuration files, or assets. At the same time, I keep in mind that while write-back improves performance, there is a brief period during which not everything has been physically saved yet.

Free RAM is cache—no loss

Many people are skeptical of „used“ memory, but I interpret the value correctly by considering the „buff/cache“ portion as a meaningful cache values. The kernel actively utilizes unused RAM, returns it to processes in a flash when needed, and manages the balance through reclaim mechanisms. This dynamic ensures that my system responds quickly as long as there is enough working set in the cache. If an application’s demand increases, the kernel evicts old cache pages and frees up space without requiring manual intervention. When I enter periods of high load, I monitor this with a focus on Storage Pressure, in order to properly assess the situation and identify bottlenecks.

Workloads that benefit greatly

I see the greatest benefits wherever data is frequently reused and there are many small accesses, which the Cache simplified. Classic examples include web servers with frequently used PHP and HTML files, as well as WordPress installations with recurring themes, plugins, media, and configurations. Databases benefit from repeated queries at the file system level, provided they do not specifically bypass the page cache. CI/CD systems with build artifacts, as well as tools that handle many small files, also see a noticeable speed boost. Even log analyses that read sequentially gain an advantage through RAM buffers, because the kernel caches access patterns and delivers them more quickly.

Monitoring and Measurement: How I Evaluate Cache Effects

First, I'll check by free -h, how large „buff/cache“ is and how occupied Memory has evolved over time. A look at /proc/meminfo shows me key metrics such as Cached, Dirty and writeback, which provide information about read operations and pending write operations. With iostat -x 1 or pidstat -d 1 I can tell if the physical I/O load drops as soon as my cache is warmed up. Tools such as perfect or bcc-based scripts help build depth, but are rarely necessary in everyday use when clear patterns are visible. In addition, I test with repeated file accesses to see if the second run is significantly faster, which demonstrates the effect of the Caches Confirmed.

Tuning: Parameters and Recommended Defaults

I only adjust what I understand, and when it comes to cache tuning, I start with a few, easy-to-understand Adjusting screws. The vm.dirty parameters control when write operations begin to be transferred from RAM to the storage medium and how aggressively this process proceeds. vm.vfs_cache_pressure Determines the extent to which the kernel overwrites Dentry and inode caches, which directly affects file system operations. Readahead values at the block device level can improve sequential read performance when workloads benefit from them. I document each step, test under load, and revert to the default values if necessary should no performance gains be observed.

Parameters Standard Effect When to change
vm.dirty_background_ratio 10% Start of the asynchronous write-back phase Let the system flood earlier when there are many small writes
vm.dirty_ratio 20% Maximum „dirty“ proportion in RAM Allow for more buffer during burst loads
vm.dirty_expire_centisecs 3000 „Dirty“ time until flush (in 1/100 s) Set a younger age for latency targets
vm.dirty_writeback_centisecs 500 Interval for Background Write-Back If storage is slow, increase it slightly
vm.vfs_cache_pressure 100 Need to clear dentries/inodes Reduce the number of file operations
Block Read-Ahead device-dependent Sequential Preview Increase for streaming reads

For a deeper understanding of the processes involved in recovery and removal, it’s worth taking a look at Page Cache Eviction, in order to thoroughly evaluate my own setup. I always implement changes step by step, monitor them using measurement points, and clearly document the effects so that every Customization remains understandable.

Page Cache and Databases: When It Makes Sense to Bypass Them

Some databases deliberately use Direct I/O to avoid double buffering and to use their own caches. In such scenarios, I work with the database’s internal parameters and rely less on the Linux page cache. If an engine frequently accesses new data or very large workloads, the bypass model is worthwhile to keep memory consumption more predictable. If, on the other hand, the focus is on repeated file reads from the same tables or indexes, the filesystem cache remains useful. I make my decision based on the actual access pattern, not on a blanket rule, so that the Performance is actually rising.

Eviction, Reclaim, and Storage Pressure

Under heavy load, the kernel sorts pages into active and inactive categories LRU Lists and gradually evicts candidates from the cache. This reclaim process responds to pressure resulting from growing process demand, cgroup limits, or I/O wait times. If my monitoring shows increased evictions alongside a rising I/O load, I recognize that the working set is larger than the available RAM. During such phases, I evaluate whether to isolate workloads, change caching strategies, or expand memory. A structured guide to the eviction rules helps me understand Storage Pressure, in order to correctly interpret symptoms and plan countermeasures.

Practical Application: Quick Checks and Commands

To give you a first impression, I'll start with free -h and read the section buff/cache, before I go into more detail. Then I'll compare two runs of a file scan, for example, using find or a benchmark, and observe the time difference between a cold start and a warm start. grep -E "Cached|Dirty|Writeback" /proc/meminfo Shows me how much is in the cache and what still needs to be written. iostat -xz 1 reveals how heavily devices are being utilized and whether the queue shortens as soon as the cache kicks in. Anyone interested in learning more about the basics of caching can find an overview in File System Caching A clear and concise introduction that explains how VFS and the RAM buffer work together.

Clearing Up Common Misconceptions

„RAM is full, the server has a problem“ is something I often hear, but the Cache This is the answer, not the cause. Linux flexibly frees up RAM when applications use it, and reclaims it as soon as new data is cached. Manually clearing it using echo 3 > /proc/sys/vm/drop_caches rarely provides lasting benefits and skews measurements. It makes more sense to identify actual hotspots and relieve the load on the I/O paths there. I also distinguish between the page cache and the slab caches for dentries/inodes so that I don't end up with two different Mechanisms Put it in a pot.

Mount Options and File System Nuances

I take into account that file system and mount options have a significant impact on page cache efficiency. atime-Updates generate additional writes; with relatime (now standard) I reduce these, noatime I save even more when I'm never limited by access times. sync and dirsync They enforce immediate persistence and negate the benefits of write-back—justified for latency-critical metadata, but otherwise I avoid them. Journaling modes (e.g., in ext4 data=ordered vs. writeback) determine whether user data is written to the storage medium before or after metadata; I prioritize security over apparent performance. XFS and btrfs behave differently when it comes to metadata and CoW: CoW, compression, or deduplication save on I/O but can consume CPU resources. I therefore measure workloads realistically and decide whether mount options align with the access pattern.

Containers, VMs, and Duplicate Caches

In containers, all processes share the same kernel—and thus the same page cache. This makes it easier to share hot files (e.g., libraries), but strict cgroup limits (memory.max) can flush cached pages early. I allocate headroom for each service and use memory.low, to provide some protection for important caches. In VMs, there are two Caches: in the guest and, if applicable, on the host (for file backings). This results in duplicate caching. If I use raw devices or direct storage, I avoid the host cache but lose its benefits. Ballooning and overcommit affect reclaim in the guest—I monitor whether constant ballooning leads to cache thrashing and adjust resources or sizing accordingly. With container storage (OverlayFS), I preheat frequently used layers so that deployments don’t start from a cold state.

NUMA, cgroups, and Isolation

On NUMA systems, the kernel maintains LRU lists for each node. If threads primarily access data locally, page cache hits remain numa-nah and reduce latency. I use CPU and memory affinity to ensure that an application and its data are located close to each other. Through memcg (cgroups v2) the page cache is assigned to a group; with memory.high I trigger a controlled reclaim using memory.max I set strict limits and with memory.low I prioritize important services. These tools help ensure that a noisy batch job doesn't flush the cache of a latency-sensitive web service. Isolation makes planning easier—but I strike a balance so that too many small caches don't end up being created, each of which would yield too few hits.

SSDs, HDDs, and Readahead in Practice

Readahead is beneficial for sequential patterns, but often just a burden for random accesses. On HDDs, I typically increase readahead to speed up linear scans. On fast NVMe SSDs, the benefit is smaller; too much readahead wastes RAM and degrades cache hits because unused pages displace others. I adjust readahead per device and run repeated tests to see if throughput or latencies improve. I also pay attention to the I/O scheduler: „none“/„mq-deadline“ is common for NVMe, while HDDs can benefit from deadline scheduling. The page cache smooths out I/O profiles, but the block layer must be configured accordingly. The goal remains for the cache to contain primarily useful, reused data—not just pre-fetched bytes.

Cold Starts, Prewarming, and Deployments

Every cache needs a warm-up phase. After reboots or rollouts, I specifically load hotsets—for example, by sequentially iterating through important directories once. This noticeably reduces the „cold minute“ following deployments. In rolling deployment strategies, I keep at least one warm instance online so that the overall service responds quickly while new instances fill their caches. I avoid mass changes to the file tree (e.g., changing paths) because that causes dentries and inodes to go cold. Instead, I use atomic symlink switches or copy-on-write strategies, where file contents and paths remain largely stable. This ensures that not only does the page cache remain effective, but the metadata caches also retain their effectiveness.

Measurements at Depth

Besides /proc/meminfo For a detailed diagnosis, I take a look at /proc/vmstat: Counters such as pgfault and pgmajfault distinguish between minor and major page faults, nr_active_file/nr_inactive_file show the size of the file-based working set, and workingset_refault helps identify thrashing. If refaults increase while the device I/O rate remains high, the work set does not fit into RAM. I test using two runs of the same workload: The second run should be significantly faster if the cache is effective. To ensure reproducible cold-start tests, I clear caches exclusively in a lab setting and document this thoroughly so as not to skew production measurements. It’s important to me not to overinterpret a single metric, but rather to identify patterns across time series.

Avoiding Swap, Swappiness, and Thrashing

Under pressure, Linux first clears the page cache before moving on to anonymous pages—as long as that makes sense. If RAM becomes scarce for processes and there aren't enough free anonymous pages, the system begins to swap. A too low Swappiness can cause important anonymous memory (heaps/stacks) to be aggressively retained, displacing useful cache pages in the process, which drives up I/O. A too high Conversely, excessive swapping leads to earlier offloading and latency spikes. I choose moderate values, measure, and monitor: The goal is for my hot set to remain in RAM, with only cold, rarely used data being offloaded to swap—never the hot data.

Security and Durability: Data on the Storage Medium

Write-back improves performance but creates a brief window during which changes are stored only in RAM. For data that must be persistent immediately, I use fsync() or fdatasync(). I also rely on safe defaults such as write barriers and journaling; I avoid risky options that disable these barriers. At the storage level, I pay attention to controller caches: write-back policies with a battery or capacitor are fast and secure, but unsecured caches without protection are risky. System-wide, I enforce sync Flushing all data—a rough-and-ready tool that I use sparingly and only when necessary. This way, I combine the speed provided by the page cache with clean persistence where it’s business-critical.

WordPress and Web Stacks: Practical Tips

Caches accumulate in the web stack: The Linux page cache accelerates static assets, PHP files, and configurations, while a PHP opcode cache keeps the execution path and bytecode in memory. I ensure that deployments don’t constantly change the code path and reduce file accesses by bundling assets. A persistent object cache layer reduces database I/O, allowing the filesystem cache to serve the remaining hot files even more effectively. Whenever possible, I avoid storing sessions and transients on the local disk, opting instead for memory or network caches so that the page cache can leverage its strengths with the remaining, frequently read files. The result: less physical I/O, faster responses, and more stable latencies.

Briefly summarized

The Linux page cache provides me with fast file responses RAM and significantly reduces costly accesses to the storage device. Read hits speed up applications, while write-back bundles many individual writes and boosts efficiency. Free memory isn't left idle but serves as a cache for a responsive platform. With metrics such as free -h, /proc/meminfo and iostat I can see the effect before I consider parameters such as vm.dirty_ratio or vm.vfs_cache_pressure Go ahead. Anyone who understands workloads, tests changes in a controlled manner, and uses the cache strategically will achieve a noticeably better Performance without any code changes.

Current articles