Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

缓冲与页面缓存

复习

  • 目录与路径:用树形名字组织大量文件
  • 文件怎样落到磁盘:数据块、元数据和索引节点的基本关系
  • 文件分配与空闲空间:数据块怎样找到、占用和回收

TL;DR

  • 磁盘很慢,直接读写会让程序等很久
  • 用内存做缓冲,暂存要读写的数据
  • 页面缓存把最近访问的磁盘块留在内存里,再访问就命中
  • 写操作也可以先在内存里攒着,合适时再一次性写回磁盘

正文

  磁盘比内存慢成千上万倍。如果每次读写都老老实实等磁盘,程序会慢得难以忍受。于是又轮到那个熟悉的词登场:缓存

缓冲

  最基本的做法是缓冲(buffering):在内存里留一小块地方,作为数据的中转站。

  • 读:先把要用的数据从磁盘读进缓冲区,程序从缓冲区取
  • 写:程序先把数据写进缓冲区,再由系统在合适的时候写到磁盘

  这样一来,程序不必每次都直接面对慢吞吞的磁盘。而且如果发现“接下来可能还要用”,还能一次多读一点。

页面缓存

  把缓冲的思路放大,就得到了页面缓存(page cache):内核把最近访问过的磁盘块,按页的形式留在内存里。

  • 读请求来了,先看页面缓存里有没有
  • 命中:直接从内存返回,根本不碰磁盘
  • 缺失:才去磁盘读,读回来顺便存进缓存,供下次使用

  因为访问有局部性,命中率往往很高,磁盘访问次数因此大幅下降。注意,这和我们前面讲的“页缓存”其实是同一套思路在不同层级的应用:地址转换有 TLB,内存访问有 CPU 缓存,磁盘访问就有页面缓存——哪里慢,就在它前面加一层快缓存

写也要讲究

  写操作如果每次都立刻写磁盘,依旧会很慢。于是通常允许延迟写

  • 数据先写进页面缓存,标记为“脏”(和磁盘不一致)
  • 攒一攒,合并相邻的写,等到合适时机再统一写回磁盘

  好处是:多次小写可以合并成一次大写,磁盘效率高得多。代价是:数据在写回之前只存在于内存,一旦此时断电,就可能丢失——这正是下一章要面对的问题。

思考题

  “延迟写”能大幅提升性能,但也带来风险。如果系统在数据还没写回磁盘时断电,会发生什么?这和数据库、编辑器的“保存”有什么相似之处?

小结

知识点

  • 缓冲:内存中转,减少直接面对磁盘
  • 页面缓存:把最近访问的磁盘块留在内存
  • 命中直接返回,缺失才访问磁盘
  • 延迟写:攒着并合并写,提升效率但有丢数据风险

参考资料

  1. Wikipedia(zh):页面缓存:page cache
  2. Wikipedia(zh):缓冲区:buffer

思考题答案(仅供参考)

  数据还没写回磁盘,就只存在于内存里。断电会让内存内容全部丢失,于是这些“以为已经保存”的数据其实没了。这和很多软件的“保存”一样:点了保存,数据往往先进了操作系统的缓存,并不立刻落到磁盘;所以重要文件写完,常需要“安全弹出”或等待写回完成。理解“缓存里的数据还不是真的安全”,能帮我们避免很多数据丢失的坑。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪