1. Overview
In this article, we’ll talk about the buffer cache. The buffer cache is a memory region that Linux uses to make read operations faster. We’ll first go over the basics of the buffer cache and the reasons why we need it. Next, we’ll go over how to clear it, to reclaim the occupied memory. Finally, we’ll show how to restrict its size.
2. The Buffer Cache
At its core, every computer program reads and writes data. The speed at which data is transferred varies depending on the medium, and it greatly affects the overall performance and the response times experienced by users. For this reason, Linux tries to minimize the number of I/O operations with those buffer caches.
Buffer caches live in memory, thus reading and writing to them is much faster compared to disks. For this reason, instead of going to the disk every time, Linux performs those write operations to those buffer caches. It then does some bookkeeping so that it knows which piece of data is cached, and it schedules regular flushes of that data onto the actual disks.
While using buffer caches can greatly improve the overall performance, they can sometimes claim a significant part of the main memory. This can add additional latency when we want to reclaim that memory and is therefore negatively impacting the running processes. In the following sections, we’ll examine how to mitigate that side-effect by manually clearing those caches and restricting the maximum size that they can occupy.
3. How to Clear the Buffer Cache
Imagine that we intend to launch a process that needs most of the available physical memory on our machine. Based on what we discussed in the previous section, Linux would have to flush the buffer caches onto the disk to reclaim this memory. This, however, takes time and thus can cause significant delays. To solve this issue, we can proactively flush those caches.
To do that, we need to write to the drop_caches file in procfs. Let’s see how to do this:
$ echo 3 > /proc/sys/vm/drop_caches
Note that the drop_caches file within procfs allows us to choose which type of buffer cache files we want to flush.
4. How to Restrict the Size of the Buffer Cache
In the previous section, we saw how to clear the buffer cache. While this does the job, it requires manual action every time. A better approach would be to prevent the buffer cache from growing in the first place. In the next two sections, we’ll show two different ways of doing that.
4.1. Increasing the Value of vm.vfs_cache_pressure
We can tell Linux to be more aggressive in getting back the memory it uses to cache some virtual filesystem objects. More specifically, we can increase the value in the/proc/sys/vm/vfs_cache_pressure file to tell Linux to reclaim back the memory** from dentry and inode objects faster compared to pagecache and swap. Inodes and dentries are data structures within the Linux Kernel that represent files and directories, respectively.
The default value of that sysfs option is 100. Setting this to a greater value, like 150 or 200, on systems running data-intensive applications has been known to help. We can do that using the following command:
$ echo 150 > /proc/sys/vm/vfs_cache_pressure
4.2. Setting an Absolute Limit in cgroups
Another way to limit the amount of memory that buffer caches use is via control groups (also referred to as cgroups). cgroups provide a way to group one or more processes to limit the resources they use. We can therefore leverage that feature to set an upper limit on how much memory a process can get. Let’s see how to create a new cgroup and set the maximum memory that processes belonging to that group can get.
First of all, we need to find out if we’re using cgroups v1 or v2, as the option changes depending on that version. Here, we’ll focus on cgroups v2 as this is more recent. The instructions for cgroups v1 are quite similar.
We’ll start by creating a new cgroup named foo:
$ sudo cgcreate -t $USER:$USER -a $USER:$USER -g memory:/foo
If the above command is not available, we may need to install cgroup-tools or libcgroup, depending on our distro. Next, let’s set the upper limit to 2 GB for that cgroup:
$ sudo echo 2G > /sys/fs/cgroup/foo/memory.max
Note that this limit should always be a multiple of the kernel page size. This is why it won’t be exactly 2 GB. We can verify that this limit is in place with the following command:
$ cgget -g memory:/foo/ | grep memory.max
memory.max: 2147483648
With everything in place**,** every process that we assign to foo will occupy at most 2 GB of memory.
5. Conclusion
In this article, we learned how to restrict the size of the buffer cache. We started by showing how to tell the Linux kernel to reclaim back the buffer cache memory more aggressively. We then leveraged cgroups to set an upper limit on the amount of memory a process can get.