/ 编程

free 命令 buffers 和 cached

大多数 Linux 用户应该都知道通过 free 命令或者 cat /proc/meminfo 查看内存使用情况。

下面是 free 命令结果的一个示例:

             total      used     free    shared    buffers    cached
Mem:       2049916   1139976   909940       680     105628    381768
-/+ buffers/cache:    652580  1397336
Swap:            0         0        0

第一行 Mem

  • 第一列值 2049916 表示总共有多少物理内存 (total)
  • 第二列 1139976 表示已使用了多少内存 (used)
  • 第三列表示未使用的内存 (free)

第二列和第三列,即 used 和 free 的值相加,等于 total 的值。第四列表示共享内存大小。第五列和第六列分别是 buffers 和 cached,都是和缓存有关的值,为了分清二者区别,需要仔细的理一下相关的知识。

第二行 -/+ buffers/cache

  • 第一列值 652580 在 used 项的下面,它表示的是第一行 used 的值减去第一行的 buffers 和 cached 的值 (2049916 - 105628 - 381768),这意味着系统除缓存外真实占用的内存有 652580KB,因为缓存相关的内存区域在内存紧张时系统会释放掉。
  • 第二行在 free 项的值 1397336 是第一行 free 的值加上第一行 buffers 和 cached 的值 (909940 + 105628 + 381768),也就是指真正能够使用的内存,空闲内存+用于缓存的内存。

第三行就是 swap 空间的总共、已用、空闲的大小。

最主要的问题是 buffers 和 cached 分别代表什么,它们的区别是什么。为了搞清楚,需要从缓存“两端”的磁盘、内存说起。

block

块设备(block device)是可以对其中的数据进行随机寻址的硬件设备,最常见的块设备就是磁盘,另外软盘、闪存等也都是块设备。读取字符设备的数据需要一个字节一个字节按顺序以数据流的方式访问,键盘就属于字符设备。

块设备最小的可寻址单元是 sector,它的大小为 2 的 N 次方,最常见的是 512 字节。sector 大小是硬件设备的物理属性。

对于软件系统来说,逻辑最小可寻址单元是 block,block 是文件系统的一个抽象,文件系统只能以 block 的倍数的大小来访问。虽然硬件设备在 sector 级别进行寻址,但是 Linux 内核执行的所有的磁盘操作都是 block 级别。

block 的大小

  • 不能小于 sector (硬件设备的最小可寻址单元)的大小
  • 不能大于内存页(physical page, 内存管理的基本单元)的大小,这是为了简化内核而做的人为限制
  • 是 2 的 N 次方

当一个 block 存储在内存里时,这块内存被称为 buffer。每个 buffer 关联一个 block,这个 buffer 代表在内存中的磁盘块。一个内存页可能包含一个或多个 block。buffer 在内核中由 buffer head (一个名为 buffer_head 的结构体)来描述。

page cache

Linux 内核的磁盘缓存叫做 page cache,把数据存储在物理内存中最大程度上减少磁盘 IO。page cache 里是 RAM 的内存页(physical page)。page cache 的大小是动态的,可能消耗掉所有未使用的内存,也可能减小以缓解机器的内存压力。

内核进行读操作时(比如某进程调用 read()),首先会检查 page cache 中的数据,如果数据在缓存中,就直接从 RAM 中读取这些数据,这是“缓存命中”。如果数据不在缓存中,就必须对磁盘进行阻塞读取操作,从磁盘读完数据后,内核会把这些数据放到 page cache,之后的读操作可能会用到。

Linux 采用 write-back 的写缓存策略,写操作直接在 page cache 上进行,不会立刻就刷新到磁盘上。写了数据的内存页标记为 dirty,放在一个列表里,这个列表里的内存页被周期性地写回到磁盘,这些内存页也就不再被标记为 dirty。

buffer cache, page cache

磁盘 block 通过 buffer 映射到内存页,这样内存页的缓存 page cache 也缓存了磁盘 block,这个缓存叫做 buffer cache,现在它基本是 page cache 的一部分。

2.4 内核之前 buffer cache 和 page cache 是分开的,前者缓存 buffer(一个磁盘 block 对应 一个 buffer),后者缓存内存页,这样就导致了磁盘 block 可能即缓存在 buffer cache 里,同时又在 page cache 里,两个 cache 可能就需要通过复制来进行同步,并且因为重复的缓存浪费了内存。对于这个情况,现在只有 page cache 了,内核用 buffer 来表示在内存中的磁盘 block,把 block 映射到内存页,而内存页在 page cache 中。

有些表示磁盘 block 的 buffer 不在 page cache 中,这里的 buffer 包含的不是文件的数据内容。例如,保存文件的元数据信息、原始的磁盘 block IO,会用到这样的 buffer。Linux 的 free 命令中 buffers 表示的就是这种 buffer 占用的内存大小。

总结起来就是,page cache 里是内存页,大部分磁盘 block(主要是常规文件) 由 buffer 映射到内存页,这部分是 buffer cache,属于 page cache 的一部分。有一小部分 buffer cache 不属于 page cache。

free

最后回到 free 命令来。

free 命令 cached 表示的是物理内存中的 page cache 占用的内存大小(page cache 可能还有部分是 swap cache,swap cache 的大小没有计算在内)。buffers 表示不属于 page cache 的那部分 buffer cache 占用的内存大小,可以想得到, buffers 的值一般都要比 cached 的值小很多。


参考: