Linux uses spare RAM to cache disk data. That’s why a server that’s barely busy can show almost no “free” memory — and why that’s usually a good sign. Understanding the cache helps you read memory statistics correctly and tune I/O-heavy workloads.

Reads: the page cache

When a process reads a file, the kernel loads the data into the page cache in RAM. The next read of the same data comes from memory, which is orders of magnitude faster than disk.

free -h
               total   used   free   shared  buff/cache   available
Mem:           3.8Gi   1.1Gi  210Mi   12Mi    2.5Gi        2.4Gi
  • buff/cache — memory holding cached file data.
  • available — what applications can actually use: free memory plus cache the kernel can drop instantly.

Watch available, not free. Low “free” with high “available” is healthy.

Writes: dirty pages and write-back

Writes normally go to the page cache first. The modified (“dirty”) pages are written to disk later by kernel flusher threads. This makes writes fast and lets the kernel combine many small writes into larger ones.

grep -E 'Dirty|Writeback' /proc/meminfo

Key settings:

Setting Default Meaning
vm.dirty_background_ratio 10 % of memory dirty before background flushing starts
vm.dirty_ratio 20 % of memory dirty before writing processes are blocked until data is flushed
vm.dirty_expire_centisecs 3000 Age (30 s) after which dirty data is flushed

On servers with lots of RAM, the percentages allow many gigabytes of unwritten data, which can cause long stalls when it’s finally flushed. Byte-based limits smooth this out:

# /etc/sysctl.d/90-dirty.conf
vm.dirty_background_bytes = 268435456   # 256 MB
vm.dirty_bytes = 1073741824             # 1 GB

Durability: fsync

Data in the page cache is lost if the server crashes or loses power. Applications that need durability — databases, mail servers — call fsync() (or open files with O_DIRECT/O_DSYNC) to force data to disk before confirming a write.

  • Databases handle this themselves; don’t disable their fsync settings in production (innodb_flush_log_at_trx_commit=1 for MySQL/MariaDB, fsync=on for PostgreSQL).
  • Your own scripts can call sync after writing important files.

Seeing the cache in action

# Drop caches (testing only — makes the next reads slow)
sync; echo 3 > /proc/sys/vm/drop_caches

time cat largefile > /dev/null   # first read: from disk
time cat largefile > /dev/null   # second read: from cache, much faster

Don’t drop caches on a production server “to free memory”; it only makes the system slower until the cache refills.

Tools to see which files are cached: vmtouch or fincore (from util-linux):

fincore /var/lib/mysql/ibdata1

I/O monitoring

iostat -xz 1          # per-device utilization, latency (r_await/w_await)
iotop -o              # which processes are doing I/O
vmstat 1              # 'bi'/'bo' blocks in/out, 'wa' I/O wait
cat /proc/pressure/io # time tasks spent waiting for I/O

Practical tuning tips

  • Give the cache room. Don’t size application memory so tightly that nothing is left for caching.
  • Use noatime on data filesystems to avoid writes on every read.
  • Databases manage their own cache (InnoDB buffer pool, PostgreSQL shared buffers) on top of the page cache. Size them deliberately — see Debian performance tuning.
  • Use a lower vm.swappiness so the kernel drops cache before swapping out application memory.

Related: Linux file system caching covers the dentry and inode caches, and Linux disk performance covers benchmarking with fio.

  • Linux
  • Performance
  • Storage