LRU算法
在限定得到空间已存满的情况下,把最久没有被访问到的数据淘汰的算法。
实现:hash表+双向链表,(LinkedHashMap)。
//重写LinkedHashMap
public class Lru1<K,V> extends LinkedHashMap<K,V> {
private static final Integer MAX = 3;
public Lru1() {
super(3,0.75f,true);
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size()>MAX;
}
public static void main(String[] args) {
Lru1<Integer, Integer> lru1 = new Lru1<>();
lru1.put(1,1);
lru1.put(2,2);
lru1.put(3,3);
lru1.get(1);
System.out.println(lru1.values());
lru1.put(4,4);
System.out.println(lru1.values());
}
}
在访问数据时,若命中,则将数据的节点移到链表的头部,若没有,则新建然后放到链表的头部,在空间满的情况将链表尾部的节点删除,然后新建放到链表头部。
缺点:若热点数据在某段时间未被访问,而非热点数据被访问的,热点数据可能会被删除。
LFU算法
在限定的空间已满的情况下,把最小频率被访问的数据淘汰,访问频率相同时,将最久未被访问的数据淘汰(类似LRU)。
实现:双hash表+双向链表。
Redis内存淘汰策略
Redis数据量过大,全部数据形成链表,消耗比较大,使用的为近似LRU和LFU的算法。
具体实现: redis定义一个淘汰池(数组,大小为16),触发淘汰策略时先从符合条件的key中随机采样5个(配置文件可配置)key,然后根据空闲时间排序放入淘汰池,每次采样后更新淘汰池,让淘汰池中保留的是key是空闲时间最长的key,在需要删除key时,将空闲时间最长的key删除。
Redis可以设置的淘汰策略:
volatile-lru:设置了过期时间的key使用LRU算法淘汰;
allkeys-lru:所有key使用LRU算法淘汰;
volatile-lfu:设置了过期时间的key使用LFU算法淘汰;
allkeys-lfu:所有key使用LFU算法淘汰;
volatile-random:设置了过期时间的key使用随机淘汰;
allkeys-random:所有key使用随机淘汰;
volatile-ttl:设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰;
noeviction:默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错(如set,lpush等),只读操作如get命令可以正常执行;