高速缓冲存储器(Cache):介于主存和CPU之间,用来存放正在执行的程序段和数据,以便CPU能高速地使用它们。
Cache的存取速度和CPU的速度相匹配。容量小,价格高,速度介于主存和CPU之间。现代计算机通常将其制作在CPU中。
1.局部性原理
(1)空间局部性
在最近的未来要用到的信息(指令和数据),很可能与现在正在使用的信息在存储空间上是邻近的。如数组元素、顺序执行的指令代码
(2)时间局部性
时间局部性:在最近的未来要用到的信息,很可能是现在正在使用的信息。如循环结构的指令代码
2.平均访问时间
设访问一次Cache所需时间为A,访问一次主存所需时间为B;欲访问信息在Cache中的比率(命中率)为P,未命中率(缺失率)为1-P
①先访问Cache,未命中再访问主存:Cache-主存系统的平均访问时间=AP+(1-P)(A+B)
②同时访问Cache和主存:平均访问时间=AP+B(1-P)
3.基于局部性原理,可以把主存的存储空间分块(如1KB),主存和Cache间以块为单位进行数据交换。当访问某一地址时,将整个块的信息调入Cache(每次被访问的主存块,一定会被立即调入Cache)
将主存空间分块,Cache也分为大小相同的块
主存地址可以用(块号,块内地址)表示
主存的“块”又叫“页/页框/页面”;Cache的“块”又叫“行”
解决主存和Cache数据块的映射关系(对应关系)。
主存中的每一个块只能装入Cache中的唯一(特定)位置。若该位置有内容,则替换出去。
优点:实现简单
缺点:不够灵活,可能造成冲突且冲突概率高,即使后面有空间也可能不用,空间利用率低
装入位置(Cache块号)=主存块号%Cache总块数
地址结构(标记,Cache行号,块内地址)
①标记:用来记录当前Cache块存放的数据来自于哪个主存块,若当前空闲标记记录为0(为防止看成是来自于0号主存块,需要增加有效位表示是否有效。如有效位1,标记0,表示当前来自于0号主存块;有效位0标记0表示当前块空闲)。
注:标记用二进制位表示,位数与主存块号位数相同。一般Cache的行数是2的整数次幂,即Cache行数=2n,即主存块号末尾的n位表示存储在Cache的行数(如n=3,主存块号末尾3位表示存储在Cache的哪一行,对于0、8…的末尾3位都是0,都存储在第0号Cache块)。可以看出,主存块号末尾的n位直接反应了它在Cache中的位置,因此为节省存储空间,标记可不存储主存块号的末尾n位,将其余位作为标记即可
②Cache行号:对Cache各块从0开始编号。主存的第0、1、2、3号块依次映射到Cache块的第0、1、2、3行
主存中的每一块可以装入Cache中的任何位置,每行的标记用于指出取自主存的哪一块,所以CPU访存时需要与所有Cache行的标记进行比较。如:主存块号22位,块内地址6位。当CPU访问某主存地址时,将前22位和Cache的标记对比,若相同,再检查有效位,若有效即可访问块内地址指定的地址单元。若Cache未命中,则正常访问主存查找。
优点:比较灵活,Cache块的冲突概率低,空间利用率高,命中率高
缺点:标记比较的速度较慢,实现成本高。通常需要采用按内容寻址的相联存储器进行地址映射
将Cache空间分成大小相同的组,主存的一个数据块可以装入一组内的任何位置,即组间采用直接映射(指定),组内采取全相联映射(任意)。
组号=主存块号%分组数
2路组相联映射:两个Cache块为一组,在此例中Cache被分为四组,即22,因此可以通过主存块号的最后两位判断属于哪个分组
CPU访存时,先找属于哪个分组(根据主存块号后n位判断),然后在指定分组中逐块对比,找到后检查有效位,若有效,即可访问块内地址指向的存储单元。若未命中则正常访问主存
Cache很小,主存很大。如果Cache满了,需要使用替换算法换入和换出。直接映射不需要考虑替换算法,全相联映射当Cache全满时才需要替换(全局替换),组相联映射当组满时才需要替换(组内替换)。
分为随机算法RAND、先进先出算法FIFO、最近最少使用算法LRU、最不经常使用算法LFU
对比操作系统的页面置换算法:最佳置换算法OPT、先进先出页面置换算法FIFO、最近最久未使用置换算法LRU、时钟置换算法CLOCK / 最近未用算法NRU、改进型时钟置换算法
操作系统的页面置换算法见:3-2内存管理-虚拟内存
随机确定替换的Cache块。实现简单,可能命中率较低。
选择最早调入的行进行替换。实现容易,但最早调入的主存块可能也是最经常使用的
Least Recently Used
往前找最近未使用过的块(手算)。选择近期内长久未访问过的Cache行作为替换的行。命中率比FIFO高,遵循了局部性原理,是堆栈类算法。若频繁访问主存块的数量大于Cache行的数量,也会产生抖动现象。
也可每行设置一个计数器(初始为0)(机器计算方式)
优势:Cache块的总数=2n,则计数器只需n位。且Cache装满后所有计数器的值一定不重复
规则:
①命中时,所命中的行的计数器清零,比其低的计数器加1,其余不变
②未命中且还有空闲行时,新装入的行的计数器置0,其余非空闲行全加1
③未命中且无空闲行时,计数器值最大的行的信息块被淘汰,新装行的块的计数器置0,其余全加1
[例] 设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}
①访问1号主存块,未命中。当前还有空闲行,新装入的行的计数器置0(Cache #0的计数器)。无其他非空闲行,不做处理
②访问2号主存块,未命中。当前还有空闲行,新装入的行的计数器置0。其余非空闲行全加1,Cache#0的计数器由0改1
③访问3号主存块,未命中。当前还有空闲行,新装入的行的计数器置0。其余非空闲行全加1,Cache#0的计数器由1改2,Cache#1的计数器由0改1
④访问4号主存块,未命中。当前还有空闲行,新装入的行的计数器置0。其余非空闲行全加1,Cache#0的计数器由2改3,Cache#1的计数器由1改2,Cache#2的计数器由0改1
⑤访问1号主存块,命中。所命中的行的计数器清零(Cache#0),比其低的计数器加1(Cache#123的计数器分别为321),其余不变
⑥访问2号主存块,命中。所命中的行的计数器清零(Cache#1),比其低的计数器加1(Cache#023的计数器分别为132),其余不变
⑦访问5号主存块,未命中,且无空闲行。计数器值最大的行的信息块被淘汰(Cache#2),新装行的块的计数器置0,其余全加1(Cache#013的计数器分别为213)
⑧访问1号主存块,命中。所命中的行的计数器清零(Cache#0),比其低的计数器加1(Cache#12的计数器分别为21),其余不变(Cache#3)
⑨访问2号主存块,命中。所命中的行的计数器清零(Cache#1),比其低的计数器加1(Cache#02的计数器分别为12),其余不变(Cache#3)
⑩访问3号主存块,未命中,且无空闲行。计数器值最大的行的信息块被淘汰(Cache#3),新装行的块的计数器置0,其余全加1(Cache#012的计数器分别为213)
⑪访问4号主存块,未命中,且无空闲行。计数器值最大的行的信息被淘汰(Cache#2),新装行的块的计数器置0,其余全加1(Cache#013的计数器分别为321)
⑫访问5号主存块,未命中。计数器值最大的行的信息被淘汰(Cache#0),新装行的块的计数器置0,其余全加1(Cache#123的计数器分别为312)
Least Frequently Used
将一段时间内被访问次数最少的存储行换出。每行设置计数器(初始为0),每访问一次计算器加1,选择计数器最小的换出。可能导致计数器的值过大,且曾经被经常访问的主存块在未来不一定会用到(LFU属于全局考虑,并非局部性考虑),因此实际中不如LRU
当两个同时(相等)最小时,可以按照FIFO算法换出,也可选择行号较小的先换出
【LRU与LFU对比】
(1)最近最少使用算法LRU(Least Recently Used):考察的是从页面最后一次被使用 到发生替换的时间长短,时间越长,页面就会被置换。LRU是(往前看)淘汰最长时间没有被使用的页面。
(2)最不经常使用算法LFU(Least Frequently Used):考察在一段时间内,使用次数(访问频率)最少的页面淘汰。
Cache中的数据只是主存数据的副本,当Cache内容更新时,需选用写操作策略使Cache内容和主存内容保持一致。
在磁盘/内存的存储区域上写过数据,且此次还要在相同地方写入数据。在此情况下,CPU要写入数据的主存块副本已经存在于Cache中,即待修改的内容可在Cache中直接找到,修改时不需要再访问主存
(1)全写法/写直通法
当CPU对Cache写命中时,必须把数据同时写入Cache和“主存”,一般使用写缓冲。当Cache块被换出时,也不需要将其再写回主存。
此方法实现简单,能随时保持主存数据的正确性。但增加了访存次数,降低了Cache的效率。
写缓冲:为减少全写法直接写入主存的时间损耗,在Cache和主存之间增加了一个写缓冲。CPU同时写数据到Cache和写缓冲中,写缓冲再控制将内容写入主存。写缓冲是一个FIFO队列,可以解决速度不匹配的问题,但可能存在写缓冲饱和导致阻塞。
(2)写回法
当CPU对Cache写命中时,只修改Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存。若未命中,则不需要写回主存。
使用此方法可以减少CPU的访存次数,但可能存在数据不一致的情况(不立即写回主存)。
需要给每一个Cache块增加一个“脏位”,若修改过,脏位置1,否则置0。标记决定了写回到主存的什么位置。
在磁盘/内存的存储区域的相同位置没有写过数据。在此情况下,CPU要写入数据的主存块不在Cache中,即待修改的内容在Cache中找不到,需要去主存中查找
(1)写分配法
当CPU对Cache写不命中时,把主存中的块调入Cache,在Cache中修改,再搭配写回法,当Cache块被换出时将其写回主存
(2)非写分配法
当CPU对Cache写不命中时,不调入Cache,直接往主存中写入数据。通常搭配全写法。在此方式下,仅读未命中时,才将其调入Cache
【多级Cache】
离CPU越近的速度越快,容量越小
离CPU越远的速度越慢,容量越大
Cache-主存之间常采用“写回法+写分配法”
各级Cache之间常采用“全写法+非写分配法”