人人都会AI编程

6.4 页缓存与缓冲区:文件缓存、磁盘缓冲的作用与区别

更新时间:2026-07-12

当 Linux 系统运行一段时间后,你可能会发现 free -h 输出中,buff/cache 占用了几 GB 甚至更多内存,而可用的 free 内存却很少。这并非内存泄漏,而是内核在主动利用空闲内存作为磁盘缓存,以大幅提升 I/O 性能。这类缓存主要分为两部分:页缓存(page cache)缓冲区缓存(buffer cache)

1. 页缓存(page cache)
页缓存用来缓存文件的内容。当你读取一个普通文件时,内核会将文件的数据页读入内存并保存在页缓存中。下次再次访问同一部分文件时,直接从内存读取,无需发起磁盘 I/O。无论是通过 cat 查看文本文件、程序加载动态库,还是数据库读取数据文件,都受益于页缓存。写文件时,数据通常也会先写入页缓存,变成“脏页”,内核再异步地将它们写回磁盘(延迟写回),从而合并多次小写操作、减少寻道和旋转延迟。

2. 缓冲区缓存(buffer cache)
缓冲区缓存用来缓存块设备的原始块,主要是文件系统的元数据(如 inode、目录块、超级块)以及绕过文件系统直接访问块设备的 I/O(比如 dd 直接操作 /dev/sda)。传统 Unix 系统中,缓冲区缓存与页缓存是两套独立机制。但在现代 Linux 内核(2.4 之后)中,它们已经统一:缓冲区缓存不再独立分配内存,而是挂在页缓存上,使用页缓存中的页来存储块数据。简化的理解:页缓存缓存的是文件在内存中的“视图”,而缓冲区缓存缓存的是磁盘上的“原始块”。访问文件时,数据必然经过页缓存;直接访问块设备(如裸设备读写、文件系统元数据操作)则使用缓冲区缓存接口。

3. 两者区别与联系

  • 对象不同:页缓存面向文件抽象,按文件偏移以页为单位;缓冲区缓存面向块设备,按扇区号以块为单位。
  • 路径不同:文件读写 → VFS → 文件系统 → 页缓存 → 最终可能通过缓冲区缓存提交 I/O;直接块设备读写 → 缓冲区缓存。
  • 查看方式free 命令中的 buff/cache 是两个的合计。buffers 对应缓冲区缓存,cached 对应页缓存。但需要注意的是,许多文件系统元数据实际上也通过页缓存管理,因此 buffers 的值通常较小,主要反映原始块设备缓存。
  • 内存回收:两者都属于可回收内存(reclaimable)。当应用程序需要更多物理内存且 free 不足时,内核会优先回收干净的缓存页;对于脏页,会先将它们写回磁盘再释放。

4. 实际观察与调优
查看详细缓存使用情况:

cat /proc/meminfo | grep -E "^Buffers|^Cached|^SwapCached"
free -h
  • Buffers:缓冲区缓存大小。
  • Cached:页缓存大小(包括文件缓存和 tmpfs 等)。
  • SwapCached:既在交换空间中又在页缓存中的页面,用于加速交换时的 I/O。

手动清空缓存(仅用于测试,生产环境切勿随意执行)

echo 1 > /proc/sys/vm/drop_caches   # 释放页缓存
echo 2 > /proc/sys/vm/drop_caches   # 释放目录项和 inode 缓存
echo 3 > /proc/sys/vm/drop_caches   # 释放上述两者

调整脏页写回行为(避免大量脏页撑爆内存)

  • vm.dirty_background_ratio:当脏页达到系统内存的此百分比时,后台开始写回。
  • vm.dirty_ratio:当脏页达到系统内存的此百分比时,写入操作会被阻塞,强制写回。
  • 通常通过 /etc/sysctl.confsysctl -w 调整。

5. 一个常见误解与实例
假设你用 dd if=/dev/zero of=/dev/sdb bs=1M count=100 直接向磁盘写数据,这部分 I/O 会经过缓冲区缓存,free 中的 buffers 可能会短暂升高。而用 cp bigfile /mnt/backup/ 复制大文件,文件内容流经页缓存,cached 数会明显增大。然而由于统一缓存机制,两种缓存背后的物理内存最终都是同一片页缓存池,区分 bufferscached 更多是出于历史原因和统计路径不同,对普通用户来说无需过度在意。

总结:页缓存与缓冲区共同构成 Linux 的磁盘缓存层,让系统能够以低速的磁盘提供高速的数据访问。理解它们的作用,不仅有助于准确解读内存使用量(free 数值低不一定表示内存紧张),还能在需要时调优写回策略,避免因大量缓存导致的内存不足或 I/O 颠簸。这是一项让 Linux 在数据库、文件服务器等 I/O 密集型场景中表现出色的关键设计。