当前位置:嗨网首页>书籍在线阅读

42-页缓存

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

2.11.2 页缓存

页缓存是通过内存保存最近在磁盘文件系统上访问过的数据的一种方式。相对于当前的处理器速度而言,磁盘访问速度过慢。通过在内存中保存被请求数据,内核后续对相同数据的请求就可以直接从内存中读取,避免了重复访问磁盘。

页缓存利用了“时间局部性(temporal locality)”原理,它是一种“引用局部性(locality of reference)”,时间局部性的理念基础是认为刚被访问的资源在不久后再次被访问的概率很高。在第一次访问时对数据进行缓存,虽然消耗了内存,但避免了后续代价很高的磁盘访问。

内核查找文件系统数据时,会首先查找页缓存。只有在缓存中找不到数据时,内核才会调用存储子系统从磁盘读取数据。因此,第一次从磁盘中读取数据后,就会保存到页缓存中,应用在后续读取时都是直接从缓存中读取并返回。页缓存上的所有操作都是透明的,从而保证其数据总是有效的。

Linux页缓存大小是动态变化的。随着I/O操作把越来越多的数据存储到内存中,页缓存也变得越来越大,消耗掉空闲的内存。如果页缓存最终消耗掉了所有的空闲内存,而且有新的请求要求分配内存,页缓存就会被“裁剪”,释放它最少使用的页,让出空间给“真正的”内存使用。这种“裁剪”是无缝自动处理的。通过这种动态变化的缓存,Linux可以使用所有的系统内存,并缓存尽可能多的数据。

一般来说,把进程内存中很少使用的页缓存“交换(swap)”给磁盘要比清理经常使用的页缓存更有意义,因为如果清理掉经常使用的,下一次读请求时又得把它读到内存中。(交换支持内核在磁盘上存储数据,得到比机器RAM更大的内存空间。)Linux内核实现了一些启发式算法,来平衡交换数据和清理页缓存(以及其他驻存项)。这些启发式算法可能会决定通过交换数据到磁盘来替代清理页缓存,尤其当被交换的数据没有在使用时。

交换-缓存之间的平衡可以通过 /proc/sys/vm/swappiness 来调整。虚拟文件数可以是0到100,默认是60。值越大,表示优先保存页缓存,交换数据;值越小,表示优先清理页缓存,而不是交换数据。

另一种引用局部性是“空间局部性(sequential locality)”,其理论基础是认为数据往往是连续访问的[9]。基于这个原理,内核实现了页缓存预读技术。预读是指在每次读请求时,从磁盘数据中读取更多的数据到页缓存中——实际上,就是多读几个比特。当内核从磁盘中读取一块数据时,它还会读取接下来一两块数据。一次性读取较大的连续数据块会比较高效,因为通常不需要磁盘寻址。此外,由于在进程处理第一块读取到的数据时,内核可以完成预读请求。正如经常发生的那样,如果进程继续对接下来连续块提交新的读请求,内核就可以直接返回预读的数据,而不用再发起磁盘I/O请求。

和页缓存类似,内核对预读的管理也是动态变化的。如果内核发现一个进程一直使用预读的数据,它就会增加预读窗口,从而预读进更多的数据。预读窗口最小16KB,最大128KB。反之,如果内核发现预读没有带来任何有效命中——也就是说,应用随机读取文件,而不是连续读——它可以把预读完全关闭掉。

页缓存对程序员而言是透明的。一般来说,系统程序员无法优化代码以更好地利用页缓存机制——除非自己在用户空间实现这样一种缓存。通常情况下,要最大限度利用页缓存,唯一要做的就是代码实现高效。此外,如果代码高效,还可以利用预读机制。虽然并不总是如此,连续I/O访问通常还是远远多于随机访问。