缓存淘汰算法

一、OPT:最佳替换算法(optional replacement)

1. 算法思想
此算法是用来评价其他算法的。永远不可实现。
算法核心是算法所淘汰的数据是以后永远不会访问的,或者是在最长时间内不再访问的那条数据。但是人们无法预知未来哪个页面才会被访问。OPT算法即为命中率最高的算法。

二、 FIFO:先进先出算法(First-in, first-out)

1. 算法思想
该算法是最简单的缓存淘汰算法。
队列的末尾存放最近添加到缓存的对象。队列的头部存放最早放进缓存的对象。
当内存满了的时候,淘汰最早放入缓存的对象。
2. 算法缺陷
FIFO算法在某些情况下会出现当所分配的物理内存增大,但是命中率反而更低的异常现象。这是因为无法判断将要访问哪个页面造成的,又称为Belady异常。仅有FIFO算法会产生这种异常。

三、 LRU:最近最久未使用算法(Least recently used)

1. 算法思想
数据结构:链表
当访问一条数据时,
如果数据在缓存中,则将该数据移动到链表头部。
如果数据不在缓存中,则把数据插入到链表头部。
如果链表满了,则把链表尾部的数据删除,然后把该数据插入到链表头部。
2. LCR-K
为了解决“缓存污染”问题。
K代表最近使用的次数。
其核心思想是将“最近使用过1次”的判断标准扩展为“最近使用过K次”。
相比LRU,LRU-K需要多维护一个队列,用于记录所有缓存数据被访问的历史。只有当数据的访问次数达到K次的时候,才将数据放入缓存。当需要淘汰数据时,LRU-K会根据LRU算法淘汰缓存链表尾部的数据。
缓存污染:是指系统将不常用的数据从内存移到缓存,造成常用数据的挤出,降低了缓存效率的现象。

472792-20161120232440279-600049881.png

实现过程:
(1). 数据第一次被访问,加入到访问历史列表;
(2). 如果数据在访问历史列表里后没有达到K次访问,则按照一定规则(FIFO,LRU)淘汰;
(3). 当访问历史队列中的数据访问次数达到K次后,将数据索引从历史队列删除,将数据移到缓存队列的头部,缓存此数据;
(4). 缓存数据队列中被再次访问后,重新排序;
(5). 需要淘汰数据时,淘汰缓存队列中排在末尾的数据
即:访问历史可按照FIFO算法或LRU算法实现。缓存链表按LRU算法实现。

LRU-K具有LRU的优点,同时能够避免LRU的缺点,实际应用中LRU-2是综合各种因素后最优的选择,LRU-3或者更大的K值命中率会高,但适应性差,需要大量的数据访问才能将历史访问记录清除掉。
3. 2Q(Two queues)
类似于LRU-2。
访问历史队列使用FIFO算法规则。
缓存链表使用LRU算法规则。

四、CLOCK:时钟算法

1. 算法思想
LRU算法的性能接近于OPT,但是实现起来比较困难,且开销大;FIFO算法实现简单,但性能差。所以有了CLOCK算法。
数据结构:循环链表
简单的CLOCK算法是给每个缓存数据关联一个访问标志位。
新添加到缓存循环链表中的数据,或者在循环链表中被访问的数据,都把访问标志位设置为1。
有个指针指向最早添加到循环链表中的数据。
当链表满了,需要删除的时候,从当前指针开始,如果当前指针指向的数据的标志位为1,则置位0,指向下一位置。直到当前指针指向的数据的标志位为0,则淘汰此数据。

实现过程
(1). 数据第一次被访问,加入到循环链表中,且将此数据的访问标志位设置为1,指针指向加入到循环链表中的第一个数据;
(2). 缓存链表第一次达到分配内存的最大值,此时指针仍旧指向最早加入循环链表中的第一个数据,所有缓存数据的标志位为1;
(3). 新访问的数据不在已满的缓存循环链表中,判断指针当前指向数据的标志位的值。如果为1,则重置为0,指针指向下一个数据。如果为0,则淘汰此数据。(第一次循环链表被填满后,所有数据的标志位都为1,此时指针指向最早被加入到循环链表中的第一个数据。然后指针根据上述规则,循环一周,把所有数据的标志位置位0,再次循环访问到最早被加入到循环链表中的第一个数据,此时该数据标志位为0,淘汰此数据)
(4). 缓存数据再次被访问,无论此时的此缓存数据的标志位是0还是1,都重新设置为1。指针不做任何变化。
(5). 数据不在缓存的循环链表中,判断指针指向的当前数据的标志位,如果为0,则淘汰此数据。如果为1,则将此数据置位0,指针指向下一个数据,继续判断标志位。

参考链接:
https://www.cnblogs.com/junyuhuang/p/5805168.html
https://www.cnblogs.com/junyuhuang/p/5993612.html
http://c.biancheng.net/cpp/html/2614.html

你可能感兴趣的:(缓存淘汰算法)