LRU 和 LFU 的区别
LRU 和 LFU 都是内存管理的页面置换算法。
LRU:最近最少使用 (最长时间) 淘汰算法(Least Recently Used)。LRU 是淘汰最长时间没有被使用的页面。
LFU:最不经常使用 (最少次) 淘汰算法(Least Frequently Used)。LFU 是淘汰一段时间内,使用次数最少的页面。
-
当需要使用页面 4 时,内存块中存储着 1、2、3,内存块中没有页面 4,就会发生缺页中断,而且此时内存块已满,需要进行页面置换。
-
若按 LRU 算法,应替换掉页面 1。因为页面 1 是最长时间没有被使用的了,页面 2 和 3 都在它后面被使用过。
-
若按 LFU 算法,应换页面 3。因为在这段时间内,页面 1 被访问了 2 次,页面 2 被访问了 3 次,而页面 3 只被访问了 1 次,一段时间内被访问的次数最少。
-
LRU 算法适合:较大的文件比如游戏客户端(最近加载的地图文件);
-
LFU 算法适合:较小的文件和零碎的文件比如系统文件、应用程序文件 ;
-
LRU 消耗 CPU 资源较少,LFU 消耗 CPU 资源较多。
例子
假设 LFU 方法的时期 T 为 10 分钟,访问如下页面所花的时间正好为 10 分钟,内存块大小为 3。若所需页面顺序依次如下:
2 1 2 1 2 3 4
---------------------------------------->
**LRU 关键是看页面最后一次被使用到发生替换的时间长短,时间越长,页面就会被置换;
LFU 关键是看一定时间段内页面被使用的频率(次数),使用频率越低,页面就会被置换。**
LRU (最长时间)
最近最久未使用算法,LRU 是淘汰最长时间没有被使用的页面
功能
- 缓存容量 capacity 为正整数,缓存的 key、value 均为 int 类型
- 读缓存
func get(key int) int:- key 已存在,返回对应 value
- key 不存在,返回 -1
- 写缓存 func put(key int, value int):
- key 已存在,修改对应 value
- key 不存在,写入该组缓存,若写入前缓存容量已达上限,则应淘汰最久未使用的缓存(强调:读、写缓存均视为使用)
数据结构
使用双向链表维护缓存的上一次使用时间:约定:链表正方向(从头部到尾部)节点按照使用时间排序——越早使用(即久未使用)的节点,越靠近链表尾部维护:每使用一次缓存,就将该缓存对应的链表节点移动到链表头部;缓存淘汰时,只需要删除尾部节点即可增加一个 map,记录
key到链表节点的映射关系; 解决如果只使用双向链表,每次判断key是否存在时,都要遍历链表
- cache:
map[int]*listNode,key到节点的映射; 其中 listNode data:key,value - list:
*listNode,双向链表,维护缓存的上一次使用时间 - capacity:
int,链表容量
伪代码
- 读缓存
- key 存在:
- 在原链表中删除该缓存节点,重新插入到链表头部,
- 返回对应的 value
- key 不存在:
- 返回 -1
- key 存在:
- 写缓存 (更新缓存)

