ARC算法分析与实现
ARC算法是2003年提出的缓存替换算法,是众多针对LRU算法的改良算法之一。
本文仅从模拟实现角度分析ARC算法,可以说就是解释ARC算法的内容,而不会将重点放在ARC算法的原理和解释其优越性上,同时代码实现也仅可用于模拟,不是针对具体应用。
FRC
ARC的结构是两个LRU队列,我们称其为 L 1 L1 L1和 L 2 L2 L2, L 1 L1 L1存储首次被访问的页,而 L 2 L2 L2存储被访问过两次及以上的页。当然这里被访问两次及以上是指在被从这两个LRU队列中淘汰之前再次被访问,因为从两个LRU队列中淘汰的页的访问就不会再被保留了。
假设我们的缓存大小为 c c c,那么两个队列总共的最大长度为 2 c 2c 2c, L 1 L1 L1队列的最大长度为 c c c,而 L 2 L2 L2在不超过最大总长度的情况下可以侵占 L 1 L1 L1的空间。自然,我们缓存不会将两个LRU中的页全部存储。ARC只存储两个LRU队列的前面一部分(假设我们把MRU一端称为前面/top,LRU一端称为后面/bottom),只有这一部分是存储具体内容的,而尾端只有页号,没有内容,不占用太多的空间。具体是前几个呢?ARC算法给出了精细的调控。
我们把 L 1 L1 L1中保存的部分称为 T 1 T1 T1( T 2 T2 T2 for L 2 L2 L2), T 1 T1 T1的长度记为 t 1 t1 t1( t 2 t2 t2 for T 2 T2 T2)。ARC为 T 1 T1 T1的长度设置了一个目标大小 p p p, 0 ≤ p ≤ c 0\leq p\leq c 0≤p≤c,这个 p p p代表了ARC更倾向于保留初次访问的数据还是再次访问的数据。当 t 1 > p t1>p t1>p时,我们优先淘汰 T 1 T1 T1中的页,当 t 1 < p t1<p t1<p时,我们优先淘汰 T 2 T2 T2中的页,总之,是让 T 1 T1 T1的长度稳定在 p p p附近(注意,新插入的页在 T 1 T1 T1还是 T 2 T2 T2中是由它是否是初次访问决定的,因此我们只能通过选择淘汰哪一个列表的页来调整 T 1 T1 T1的长度)。而当 t 1 = p t1=p t1=p时,作者表示这个时候的淘汰策略可以任意一点,如果miss页在 B 1 B1 B1中则淘汰 T 2 T2 T2中的页,否则淘汰 T 1 T1 T1中的页。
以上其实是给定 p p p的算法的简单描述,作者将这个算法称作FRC算法(Fixed Replacement Cache),那么我们的 p p p是怎么确定的呢,这就是ARC算法Adaptive的地方了。接下来我开始具体分析ARC算法。
ARC算法中包含的操作
我们可以想象两个LRU队列,在T部和B部的分界处有一块可移动的隔板,在最前端有一个可插入的缝隙。
这两个隔板之间的部分就是存储在缓存中的部分,而缝隙就是最近一次访问的页可能插入的位置。一方面,两个隔板之间的最大距离不可能超过缓存的大小,即 c c c;另一方面,我们只考虑隔板向自身队列的头部(top端)移动,在算法中不会将隔板向尾部移动,因为隔板 b 1 b1 b1向头部移动意味着 T 1 T1 T1的LRU页从缓存中删除,滚向 B 1 B1 B1,这是可能的,而隔板向尾部移动则代表 B 1 B1 B1的MRU页变成 T 1 T1 T1的LRU页,这是不可能的,这种移动没有合理性。
隔板的移动会改变缓存的长度,不会改变 L 1 L1 L1或者 L 2 L2 L2的长度;而在两个缝隙之一插入元素,则既会改变 L 1 , L 2 L1,L2 L1,L2的长度也会改变缓存的长度。除了以上两个操作,当然还有第三个和第四个操作,那就是从 L