Page Cache 是如何“诞生”的?

Page Cache 的产生有两种不同的方式:

  • Buffered I/O(标准 I/O);
  • Memory-Mapped I/O(存储映射 I/O)。

image.png

标准 I/O 是写的 (write(2)) 用户缓冲区 (Userpace Page 对应的内存),然后再将用户缓冲区里的数据拷贝到内核缓冲区 (Pagecache Page 对应的内存);如果是读的 (read(2)) 话则是先从内核缓冲区拷贝到用户缓冲区,再从用户缓冲区读数据,也就是 buffer 和文件内容不存在任何映射关系。

对于存储映射 I/O 而言,则是直接将 Pagecache Page 给映射到用户地址空间,用户直接读写 Pagecache Page 中内容

演示 Page Cache 的产生:

image.png

这个过程大致可以描述为:首先往用户缓冲区 buffer(这是 Userspace Page) 写入数据,然后 buffer 中的数据拷贝到内核缓冲区(这是 Pagecache Page),如果内核缓冲区中还没有这个 Page,就会发生 Page Fault 会去分配一个 Page,拷贝结束后该 Pagecache Page 是一个 Dirty Page(脏页),然后该 Dirty Page 中的内容会同步到磁盘,同步到磁盘后,该 Pagecache Page 变为 Clean Page 并且继续存在系统中。

生命周期 (程序产生数据, 写时):

  1. Alloc Page: Page Cache 诞生
  2. Dirty Page: Page Cache 被修改
  3. Clean Page: Page Cache 同步到磁盘

生命周期 (程序读打开文件, 读时):

  1. 读文件: Page Cache 诞生, 与磁盘一致 Clean Page

观测脏页状态:

  1. $ cat /proc/vmstat | egrep "dirty|writeback"
  2. nr_dirty 40
  3. nr_writeback 2
  • nr_dirty 表示当前系统中积压了多少脏页
  • nr_writeback 则表示有多少脏页正在回写到磁盘中
  • 单位都是 Page(4KB)

Dirty Pages 如果积压得过多,在某些情况下也会容易引发问题.

Page Cache 是如何“死亡”的?

Page Cache 的回收行为 (Page Reclaim) 理解为 Page Cache 的“自然死亡”。

查看内存使用情况:

  1. $ free -g
  2. total used free shared buff/cache available
  3. Mem: 125 41 6 0 79 82
  4. Swap: 0 0 0

free 命令中的 buff/cache 中的这些就是“活着”的 Page Cache,那它们什么时候会“死亡”(被回收)呢?我们来看一张图:

image.png

你可以看到,应用在申请内存的时候,即使没有 free 内存,只要还有足够可回收的 Page Cache,就可以通过回收 Page Cache 的方式来申请到内存,回收的方式主要是两种:

  • 直接回收
  • 后台回收

观察 Page Cache 直接回收和后台回收最简单方便的方式是使用 sar:

$ sudo pacman -S sysstat

  1. $ sar -B 1
  2. 02:14:01 PM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
  3. 02:14:01 PM 0.14 841.53 106745.40 0.00 41936.13 0.00 0.00 0.00 0.00
  4. 02:15:01 PM 5.84 840.97 86713.56 0.00 43612.15 717.81 0.00 717.66 99.98
  5. 02:16:01 PM 95.02 816.53 100707.84 0.13 46525.81 3557.90 0.00 3556.14 99.95
  6. 02:17:01 PM 10.56 901.38 122726.31 0.27 54936.13 8791.40 0.00 8790.17 99.99
  7. 02:18:01 PM 108.14 306.69 96519.75 1.15 67410.50 14315.98 31.48 14319.38 99.80
  8. 02:19:01 PM 5.97 489.67 88026.03 0.18 48526.07 1061.53 0.00 1061.42 99.99
  1. pgscank/s : kswapd(后台回收线程) 每秒扫描的 page 个数。
  2. pgscand/s: Application 在内存申请过程中每秒直接扫描的 page 个数。
  3. pgsteal/s: 扫描的 page 中每秒被回收的个数。
  4. %vmeff: pgsteal/(pgscank+pgscand), 回收效率,越接近 100 说明系统越安全,越接近 0 说明系统内存压力越大。

这几个指标也是通过解析 /proc/vmstat 里面的数据来得出的,对应关系如下:

image.png

总结

  • Page Cache 是在应用程序读写文件的过程中产生的,所以在读写文件之前你需要留意是否还有足够的内存来分配 Page Cache;
  • Page Cache 中的脏页很容易引起问题,你要重点注意这一块;
  • 在系统可用内存不足的时候就会回收 Page Cache 来释放出来内存,我建议你可以通过 sar 或者 /proc/vmstat 来观察这个行为从而更好的判断问题是否跟回收有关