《操作系统导论》中的那些缓存

阅读《操作系统导论》时,常常看到“缓存”这个词:CPU执行指令时有寄存器与高速缓存、从硬盘读取数据有磁道缓冲区、虚拟内存映射有TLB,甚至于整个内存都被称之为缓存……

工作中敲业务代码,缓存更是不可忽视的加分项,Redis是专用于缓存的数据库,浏览器自带缓存策略,甚至于Python语言还提供缓存装饰器(functools.cache)……

一切可重用的内容,都应该缓存下来。

读完《操作系统导论》,为之写下读书笔记之前,我想先理一理,书中提到的缓存。

1、各种类型存储设备的速度对比

开始整理之前,我先从第三版CSAPP(《深入理解计算机系统》)中摘抄2张关于存储设备速度进化的图片:

图片

图一

上图是3种存储设备和CPU的访问速度、造价随着年代的变化。可以看到在2015年:

  • SRAM(一般用做CPU高速缓存)的访问时间是1.3纳秒,每M字节的造价为25刀;

  • DRAM(用做内存)访问时间为20纳秒,每M字节的造价为0.02刀;

  • 旋转磁盘(机械硬盘)的寻道时间为3毫秒(3000000纳秒),每G(1000M)字节造价为0.03刀;

  • CPU有效周期时间为0.08纳秒。

由图中可以看到,不管是存储设备还是CPU,整体的趋势,是速度越来越快,价格越来越低。但几种设备之间的访问速度差距,是一直存在的。

图片

图二

图二将图一中的数字放进同一张表格,各种设备之间的差距,被更清晰地呈现出来。

由上面两张图可以看到,硬盘到CPU的距离,是一千万倍!

用一个不严谨的例子来说明这差距:如果CPU的做一次加法耗时1秒。当我们需要将存储在硬盘中的两个数字相加时,真正进行加法计算之前,CPU要等待两个数字被读进寄存器,这等待的时间,是一千万秒,近116天!

1秒的计算,需要116天的等待,这是不能接受的。

好在CPU很忙,在它忙着其它事情时,I/O系统在背后默默地将数据读进内存、读进高速缓存,让数字离CPU更近一点。

这提前读取的数字,便是缓存。

2、局部性概念

缓存能生效,是有理论支撑的,它的理论来源于局部性(locality)概念。

局部性分为两种:

  • 一是时间局部性。时间局部性是指当一个数据被访问后,它很有可能会在不久的将来被再次访问,比如循环代码中的数据或指令本身。

  • 二是空间局部性。空间局部性指的是当程序访问地址为x的数据时,很有可能会紧接着访问x周围的数据,比如遍历数组或指令的顺序执行。

由于这两种局部性存在于大多数的程序中,硬件系统可以很好地预测哪些数据可以放入缓存,从而运行得很好。显然,有良好局部性的程序比局部性差的程序运行得更快

现代计算机系统的各个层次——从硬件到操作系统再到应用程序——的设计都利用了局部性。在硬件层,局部性原理允许计算机设计者通过引入称为高速缓存存储器的小而快速的存储器来保存最近被引用的指令和数据项,从而提高对内存的访问速度。

在应用程序级,Web浏览器将最近被引用的文档放在本地磁盘上,利用的就是时间局部性。大容量的Web服务器将最近被请求的文档放在前端磁盘高速缓存中,这些缓存能满足对这些文档的请求,而不需要服务器的任何干预。

在操作系统级,局部性原理允许系统使用内存作为虚拟地址空间最近被引用块的高速缓存。类似地,操作系统用内存来缓存磁盘文件系统中最近被使用的磁盘块。

本篇文章,便将操作系统级使用到的缓存做一次简单汇总。

3、操作系统中用到的缓存

在《操作系统导论》这本书中,提到过的缓存有以下几种类型:

  • CPU缓存

  • TLB

  • 磁盘缓存

  • 文件系统缓存

  • 分布式系统缓存

3.1、CPU缓存

CPU缓存,是除了寄存器之外最靠近CPU的存储设备。存在多级结构,在我们配电脑时,经常看到的L1、L2、L3,即是CPU缓存。

CPU缓存,是很小很快的存储设备,通常拥有内存中最热的数据的备份。对于CPU来说,它获取数据,是直接从缓存中拿的。

程序第一次读取数据时,数据在内存中,因此需要花费较长的时间(可能数十或数百纳秒)。处理器判断该数据很可能会被再次使用,因此将其放入CPU缓存中。如果之后程序再次需要使用同样的数据,CPU会先查找缓存。因为在缓存中找到了数据,所以取数据快得多(比如几纳秒),程序也就运行更快。(所有级别的缓存机制,都可以套用本流程。)

CPU缓存在单CPU情况下运行就像上面摘抄内容所说:用过先存着,下次用得着。

但随着多核处理器的普及,多CPU成为行业标准,每个CPU都有自己对应的缓存设备。当两个CPU同时读写同一内存地址时,需要保证各自CPU中缓存数据与内存中数据一致。这种问题被称为缓存一致性(cache coherence)问题,是普遍存在的需要被认真对待的问题。

CPU缓存级别的缓存一致性问题,通过硬件监控内存访问来避免,除此之外,还会在操作系统级别加锁。

3.2、TLB

TLB,地址转换旁路缓冲存储器(translation-lookaside buffer),是频繁发生的虚拟到物理地址转换的硬件缓存(cache),是书中的大章节,也是操作系统中的很是重要的部分。

开始介绍TLB之前,书中先用18个章节介绍了进程、线程、多处理器调度、地址空间、地址转换等操作系统中所存在的基础概念。

对于一个进程来说,它所看到的内存主要分为程序代码、堆、栈三个部分,机器的真实物理内存有16G,它能看到的内存空间便接近于16G。但事实上,一个机器是不会只运行一个进程的,所以进程看到的16G内存,是虚构的。

这虚构——每个程序都拥有存放自己代码和数据的私有内存——的美丽假象,操作系统借助地址转换技术实现:进程访问真实地址A之前,需要先将它看到的虚构内存空间中的地址VA借操作系统和硬件的帮助转化为地址A。做这个内存地址转换功能的部分被统称为内存管理单元(Memory Management Unit,MMU),每次内存引用时,MMU都会进行地址转换,将应用程序的内存引用重定位到内存中实际的位置。

为了减少内部碎片(internal fragmentation),也为了分配内存能简单些,又添加了分页的概念:物理内存被看成是定长槽块的阵列,每个阵列被叫作页帧(page frame),每个这样的页帧包含一个虚拟内存页。

要使用分页,就要将内存地址空间切分成大量固定大小的单元(页),并且需要记录这些单元的地址映射信息。在转换虚拟地址时,每次指令获取、显式加载或保存,都要额外读一次内存以得到这映射信息。为了加速虚拟地址转换,尽量避免额外的内存访问,于是就有了TLB。

当进程需要访问内存时,硬件先检查TLB,看看其中是否有期望的转换映射,如果有,就完成转换(很快),不用访问页表(其中有全部的转换映射);如果没有,就访问页表,并将该转换映射存储到TLB。

一言以蔽之,TLB是缓存,是为提升操作系统进程访问内存速度而设计的缓存。

3.3、硬盘缓存

旋转磁盘对数据的读写,因为它的物理结构——一个不停转圈圈的圆盘——被分为寻道、旋转和读写三个步骤。其中寻道和旋转的耗时是很长的,如图一,15年硬盘的寻道时间为3毫秒。

为了加快磁盘的访问速度,为磁盘访问添加缓存是必不可少的,这缓存一般被称为磁道缓冲区(track buffer),该缓存只是少量的内存(通常大约8MB或16MB),驱动器使用这些内存来保存从磁盘读取或写入磁盘的数据。

借助于局部性原理,当从磁盘读取扇区时,驱动器可能决定读取该磁道上的所有扇区并将其缓存在其存储器中,如此来让驱动器快速响应所有后续对同一磁道的请求。

3.4、文件系统缓存

我们在操作系统中看到的文件,是按照规定格式(关键字有inode、数据位图、多级索引、目录组织等)存储在磁盘上的。一个普通的文件写入,可能在逻辑上导致5个I/O:一个读取数据位图(然后更新以标记新分配的块被使用),一个写入位图(将它的新状态存入磁盘),再有两次I/O,其中一次是读取inode,另一次是写inode(为了更新块的位置),最后一次写入真正的数据块本身。

为了减少I/O次数,操作系统会把文件系统中的文件元数据都缓存在内存中。

需要注意的是,文件系统的缓存与硬盘的缓存,是有区别的。硬盘缓存面向的是磁道、扇区等硬件层面的读写,而文件系统缓存面向是文件的组织形式。

3.5、分布式系统缓存

随着Internet发展,出现了越来越多的客户端/服务器分布式系统。很多客户端同时操作的对象,是远端的同一台机器,这中间会用到网络传输。

而网络传输的速度,是很慢的,甚至于比访问硬盘更慢。

所以分布式系统中的缓存设计,也是必不可少的。书中对这部分的内容,介绍的并不多,主要的讨论点在于:缓存内容是全部还是局部。

4、小结

以上,是我读完《操作系统导论》后对缓存的认知整理。

在整个计算机世界中,缓存无处不在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值