缓存数据淘汰算法LRU 和 LFU
本文由 AI 生成,内容仅供参考,请仔细甄别。
一、什么是缓存淘汰算法?
缓存空间是有限的,当缓存已满又需要新增数据时,需要一个策略决定“谁被淘汰(evict)”。
二、LRU(最近最少使用)
📌 全称:Least Recently Used
📘 核心思想:
最近最少使用的数据优先被淘汰。
也就是说,很久没被访问的数据会被认为“不重要”,优先移除。
📈 应用场景:
- 适合访问具有时间局部性的场景(最近访问过的数据还可能被再次访问)
- 常见于:Redis 默认淘汰策略、操作系统页面置换(如 Linux 的 page cache)
🛠️ 实现方式:
- 通常用 双向链表 + HashMap
- Java 中:
LinkedHashMap
就可以实现 LRU 缓存 - 现代高性能实现(如 Caffeine)使用 分段队列 + 时间窗口优化
✅ 优点:
- 简单、高效
- 适用于大多数缓存场景
❌ 缺点:
- 无法区分访问频率 → 可能会淘汰热点但“间隔长”的数据
三、LFU(最不经常使用)
📌 全称:Least Frequently Used
📘 核心思想:
访问次数最少的数据优先被淘汰。
也就是说,“用得不多”的数据会被优先淘汰,哪怕它刚刚访问过。
📈 应用场景:
- 数据访问具有 频率热点特征 的场景(如部分热门商品/文章访问次数远高于其他)
- 比如新闻首页最热榜、搜索缓存等
🛠️ 实现方式:
- 常用结构:最小堆 + HashMap
- 或:频率分桶法(frequency-bucket + 双链表)
- Java 高性能实现:Caffeine 支持近似 LFU
✅ 优点:
- 保留使用频率高的数据,更适合“冷数据很多”的场景
❌ 缺点:
- 实现复杂
- 频率需要定期衰减(否则冷数据可能因早期频繁访问而“常驻”)
四、LRU vs LFU 对比总结
特性 | LRU | LFU |
---|---|---|
策略核心 | 最近最少使用 | 最少访问次数 |
关注点 | 时间顺序 | 访问频率 |
数据保留倾向 | 最近用过的数据 | 访问次数多的数据 |
热点识别能力 | 一般(只看是否“最近”) | 强(会识别长期热点) |
实现复杂度 | 简单(双向链表 + HashMap) | 复杂(频率桶 + HashMap + 最小堆等) |
适合场景 | 普通缓存、短期热点 | 长期热点识别、高性能缓存(如 Caffeine) |
五、简单代码对比(Java 示例)
🔹 LRU 简单实现(基于 LinkedHashMap
):
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true); // accessOrder = true 实现 LRU
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
🔸 LFU 实现略复杂,推荐使用开源工具:
- Caffeine(支持 LRU + LFU 的现代 Java 缓存框架)
- Redis:从 Redis 4.0 开始支持 LFU 模式(需配置
maxmemory-policy
为allkeys-lfu
)
六、扩展:其他常见缓存策略
策略名 | 全称 | 简要说明 |
---|---|---|
FIFO | First In First Out | 最先加入的先被淘汰(简单但容易误判重要数据) |
ARC | Adaptive Replacement Cache | 综合 LRU 和 LFU,自适应调整 |
Random | 随机淘汰 | Redis 支持,适用于极端高性能要求场景 |
七、总结
- 如果你希望缓存保留 “最近使用过” 的数据:选 LRU
- 如果你希望缓存保留 “访问频率高” 的数据:选 LFU
- 如果对命中率要求更高,建议用现代实现(如 Caffeine,它做了 LRU+LFU 混合优化)