① lru算法是什么呢
LRU算法是最少使用页面置换算法(Least Recently Used),首先置换近期最长时间以来没被访问的页面,是为虚拟页式存储管理服务的。
LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
LRU原理
该思想最初用于计算机操作系统中,内存中的容量较有限,为了能更加合理的利用内存中的性能,对用户的使用作出假设,最近最少使用的越不重要,最近使用的越有可能使用到,使得该元素更容易获取到。
如果元素当前容量超过了内存最大容量,则需要删除掉最近最少使用的元素。在其之后,许多缓存及许多分布式系统都采用才思想。
② lru算法是什么
lru算法是一种页面置换算法,在对于内存中但是又不用的数据块,叫做LRU,操作系统会根据那些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。
LRU算法:最近最少使用,简单来说就是将数据块中,每次使用过的数据放在数据块的最前端,然后将存在的时间最长的,也就是数据块的末端的数据剔除掉这就是LRU算法。
如果进程被调度,该进程需要使用的外存页(数据)不存在于数据块中,这个现象就叫做缺页。如果这个数据此时不在,就会将这个数据从加入到数据块首部。
数据块插入与剔除:每次有新数据到来时,会将其放入数据块首部,当数据每次被访问时,将这个数据插入数据块的首部如果数据块满了,每次新进的数据都会将数据块尾部的数据挤出数据块。
差距
为了尽量减少与理想算法的差距,产生了各种精妙的算法,最少使用页面置换算法便是其中一个。LRU算法的提出,是基于这样一个事实:在前面几条指令中使用频繁的页面很可能在后面的几条指令中频繁使用。
反过来说,已经很久没有使用的页面很可能在未来较长的一段时间内不会被用到。这个,就是着名的局部性原理——比内存速度还要快的cache,也是基于同样的原理运行的。因此,我们只需要在每次调换时,找到最少使用的那个页面调出内存。这就是LRU算法的全部内容。
LRU在电子系统中的解释:
Line Replaceable Unit—LRU,电子系统中常采用模块化设计,这种可更换的模块单元则被叫做LRU,中文名称是“线性可更换单元”。
③ 页面置换算法之LRU算法
三种常见的页面置换算法:FIFO、LFU、LRU
参考:
缓存算法(页面置换算法)-FIFO、LFU、LRU
LRU(Least Recently Used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是: 如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小 。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
假设 序列为 4 3 4 2 3 1 4 2
物理块有3个 则
首轮 4调入内存 4
次轮 3调入内存 3 4
之后 4调入内存 4 3
之后 2调入内存 2 4 3
之后 3调入内存 3 2 4
之后 1调入内存 1 3 2(因为最少使用的是4,所以丢弃4)
之后 4调入内存 4 1 3(原理同上)
最后 2调入内存 2 4 1
如果让我们设计一个LRU Cache的数据结构,它应该支持两个操作:
一种是采用数组来存储每个数据项,再对每个key关联一个时间戳,在cache中维护一个最大时间戳,其设计要点如下:
另一种是采用hashmap+双向链表的数据结构,其设计要点如下:
对比上一节的两种设计思路,不难发现,设计1需要为每个key维护一个时间戳,而且set和get操作的时间复杂度都是O(n)。显而易见,随着数据量的增大,set和get操作的速度越来越慢。而设计2通过采用hashmap+双向链表,set和get操作的时间复杂度只需O(1),下面给出设计2的具体实现。
运行结果为:
参考:
LRU Cache
LRU原理和Redis实现——一个今日头条的面试题
④ 编译原理LRU分析法
(2)LRU算法,也是往前看。前四次缺页,第五、六次满足;第七次1出5进;第第八次2出1进;第九次3出2进;第十次4出3进;第十一次5出4进;第
⑤ 实现LRU算法的硬件支持是什么
寄存器、栈
实现LRU算法的硬件支持是寄存器、栈。寄存器用于记录某进程在内存中各页的使用情况;栈用于保存当前使用的各个页面的页面号。LRU是最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发器来构成。
(5)分析lru算法实现思路扩展阅读:
大部分操作系统为最大化页面命中率而广泛采用的一种页面置换算法是LRU算法。该算法的思路是,发生缺页中断时,选择未使用时间最长的页面置换出去。从程序运行的原理来看,最近最少使用算法是比较接近理想的一种页面置换算法,这种算法既充分利用了内存中页面调用的历史信息,又正确反映了程序的局部问题。
⑥ FIFO和LRU小结
一:FIFO算法
1.0,FIFO (First in First out) 先进先出(核心原则:最先进来的,最先淘汰); 其实在操作系统的设计理念中很多地方都是利用到了先进先出的思想就是因为这个原则简单切符合人们的惯性思维,具备公平性实现起来也简单,直接使用数据结构中的队列即可实现
1.1,在FIFO 中应该支持这些操作: 一,get(key),如果Cache中存在该key,则返回对应的value值,否则返回 -1; 二,set(key,value),如果Cache中存在该key,则重置value值,如果不存在则将该key插入到Cache中,若Cache已满则淘汰最先进入Cache的数据
1.2,那么利用什么数据结构来实现呢?有这一种思路, 利用一个双向链表保存数据,当来了新数据之后便添加到链表末尾,如果Cache存满数据,则把链表头部数据删除,然后把次年数据添加到链表末尾,在访问数据的时候,如果在Cache中存在该数据的话,则返回对应的value值,否则返回 -1,如果想提高访问效率,可以利用hashmap来保存每个key在链表中的位置(参考下面拓展)
二:LRU算法
1.0,LRU (Least recently used) 最近最久未使用调度,其核心思想是"如果数据最近被访问过,那么将来被访问的几率也更高"; 最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
1,新数据插入到链表头部
2,每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
3,当链表满的时候,将链表尾部的数据丢弃
1.1,LRU的优缺点 1.命中率,当存在热点数据时,LRU的效率很好,但偶发性的,周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重 2,实现相对简单 3,命中时需要遍历链表,找到命中的数据块索引,然后需要将数据移到头部
2.0,LRU-K K代表最近使用的次数,因此LRU也可以认为是LRU-1,它主要是为了解决LRU算法"缓存污染"的问题,其核心思想是将"最近使用过1次"的判断标准扩展为"最近使用过K次"; 相比LRU要多维护一个队列,用于记录所有缓存数据被访问的历史,只有当数据的访问次数达到K次的时候,才将数据放入缓存.当需要淘汰数据时,LRU-k会淘汰第K次访问时间距离当前时间最大的数据.详细实现如下:
2.1,一,数据第一次被访问,加入到访问历史列表; 二,如果数据在访问历史列表里后达到K次访问,则按照一定(FIFO, LRU)淘汰; 三,当访问历史队列中的数据访问次数达到k次后,将数据l索引从历史队列删除,将数据移到缓存队列中,并缓存此数据,缓存队列重新按照时间排序; 四,缓存数据队列中被再次访问后,重新排序; 五,需要淘汰数据时,淘汰缓存队列中排在末尾的数据(即:淘汰倒数第K次访问离现在最久的数据)
2.2,LRU-K具有LRU的优点,同时能够避免LRU的缺点,实际应用中LRU-2是综合各种因素后最优的选择,LRU-3或者更大的K值命中率会高,但适应性差,需要大量的数据访问才能将历史记录缓存或者清除掉
2.3优缺,LRU-K降低了"缓存污染"带来的问题,命中率比LRU要高,但LRU-K队列是一个优先级队列,算法复杂度和代价相对LRU较高,并且LRU需要记录那些被访问过,但是没有达到K次也就是还没有放入缓存的对象,因此b内存消耗会比LRU要多,当然如果数据量很大的时候,内存消耗会比较可观
3.0,Two queues (2Q) 算法类似于LRU-2,不同点在于2Q将LRU-2算法中的访问历史队列(历史队列,还没有缓存数据)改为一个FIFO缓存队列,即: 2Q算法有两个缓存队列,一个是FIFO队列,一个是LRU队列.
3.1,当数据第一次访问时,2Q算法会将数据缓存在FIFO队列里面,当数据第二次被访问时,则将数据从FIFO队列移到LRU队列里面,两个队列各自按照自己的方法淘汰数据; 一,新访问的数据插入到FIFO队列, 二,如果数据在FIFO队列中一直没有被再次访问,则最终按照FOFO规则淘汰, 三,如果数据在FIFO队列中被再次访问,则将数据移到LRU队列头部, 四,如果数据在LRU队列再次被访问,则将数据移到LRU队列头部, 五,LRU队列淘汰末尾的数据
3.2,可能会感觉FIFO队列比LRU队列短,但并不代表这是算法的要求,实际应用中两者比例没有硬性要求
3.3,2Q算法命中率高于LRU,切需要两个队列,但两个队列本身都比较简单,代价是FIFO和LRU代价之和; 2Q算法和LRU-2算法命中率类似,内存消耗也比较接近,但对于最后的缓存数据来说,2Q减少一次从原始储存读取数据或者计算数据的操作
4.0,Multi Queue (MQ) 算法根据访问频率将数据划分为多个队列,不同的队列具有不同的访问优先级,其核心思想是:优先缓存访问次数多的数据
4.1,MQ算法将缓存划分为多个LRU队列,每个队列对应不同的访问优先级,访问优先级是根据访问次数计算出来的,详情: 一,新插入的数据放入Q0; 二,每个队列按照LRU管理数据; 三,当数据访问次数达到一定次数需要提升优先级时将数据从当前队列删除,加入到高一级的队列头部; 四,为了防止高优先级数据永远不被淘汰,每个队列淘汰数据时,将数据从缓存中删除,将数据加入Q-history头部; 五,需要淘汰数据时,从最低一级队列开始按照LRU淘汰,每个队列淘汰数据时,将数据从缓存中删除,将数据索引加入Q-history头部; 六,如果数据在Q-history中被重新访问,则重新计算其优先级,移到目标队列的头部; 七,Q-history按照LRU淘汰数据的索引
4.2,MQ降低了"缓存污染"带来的问题,命中率比LRU高,但MQ需要维护多个队列,切需要维护每个数据的访问时间,复杂度比较高,并且MQ需要记录每个数据的访问时间,需要定时扫码所有队列,代价也比较高
4.3,虽然MQ的队列看起来数量比较多,但由于所有队列之和受限于缓存容量的大小,因此这里多个队列长度之和和一个LRU队列是一样的,因此队列扫码性能接近
小结: 命中率 LRU-2 > MQ(2) > 2Q > LRU ; 复杂度 LRU-2 > MQ(2) > 2Q >LRU ; 代价 LRU-2 > MQ(2) > 2Q > LRU ; 需要注意的是,命中率并不是越高越好,实际中应该根据业务需求和对数据的访问情况进行分析选择,LRU虽然看起来命中率低一些,切存在"缓存污染"的问题,但其简单切代价小,实际中反而应用更多
拓展:基于 双链表的 LRU 实现: 一,传统意义的LRU算法是每一个Cache对象设置一个定时器,每次Cache命中则给定时器 +1,而Cache用完需要淘汰旧内容,放置新内容时就查看所有的计时器,并将使用的内容替换掉; 其弊端很明显,如果Cache的数量少,问题不大,但如果Cache的空间过大,达到10W或者100W以上,一旦需要淘汰,则需要遍历所有计时器,其性能与资源消耗巨大,效率也就非常的慢了; 二,双链表原理,将Cache的所有位置都用双链表连接起来,当一个位置被命中之后,就将通过调整链表的指向,将该位置调整到链表头的位置,新加入Cache直接加到链表头中,这样在多次进行Cache操作后,最近被命中的就会被向链表头方向移动,而没有命中的则向链表后部移动,链表尾则表示最近最少命中的Cache,当需要替换内容时我们只需要淘汰链表最后的部分即可!
如果错误或者建议,欢迎下方留言,谢谢!