Cache —— 替换算法和写策略

本文深入探讨了缓存管理的关键技术,包括替换算法如随机算法、先进先出算法、近期最少使用算法和最不经常使用算法,以及缓存写策略如全写法、写回法、写分配法和非写分配法。文章还介绍了写缓冲的作用和含有两级缓存系统的优点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、替换算法

在采用全相联映射和组相联映射方式时,从主存向 Cache 传送一个新块,当 Cache 中的空间被占满时,就需要使用替换算法置换 Cache行。而采用直接映射则不需要考虑替换算法。

  1. 随机算法(RAND):随机地确定替换的Cache块。它的实现比较简单,但没有依据程序访问的局部性原理,故可能命中率较低。
  2. 先进先出算法(FIFO):选择最早调入的行进行替换。它比较容易实现,但也没有依据程序访问的局部性原理,可能会把一些需要经常使用的程序块(如循环程序)也作为最早进入Cache的块替换掉。
  3. 近期最少使用算法(LRU):依据程序访问的局部性原理选择近期内长久未访问过的存储行作为替换的行,平均命中率要比FIFO要高,是堆栈类算法。LRU算法对每行设置一个计数器,Cache每命中一次,命中行计数器清0,而其他各行计数器均加1,需要替换时比较各特定行的计数值,将计数值最大的行换出。
  4. 最不经常使用算法(LFU):将一段时间内被访问次数最少的存储行换出。每行也设置一个计数器,新行建立后从0开始计数,每访问一次,被访问的行计数器加1,需要替换时比较各特定行的计数值,将计数值最小的行换出。

在二路组相联映射中采用 FIFO 替换算法:
在这里插入图片描述

在二路组相联映射中采用 LRU 替换算法:

在这里插入图片描述


二、Cache 写策略

因为 Cache 中的内容是主存块副本,当对 Cache 中的内容进行更新时,就需要选用写操作策略使得 Cache 内容和主存内容保持一致。此时分为两种情况。

Cache 写命中的处理方法

(1)全写法

当 CPU 对 Cache 写命中时,必须把数据同时写入 Cache 和主存。当某一块需要替换时,不必把这一块写回主存,用新调入的块直接覆盖即可。

(2)写回法

当 CPU 对 Cache 写命中时,只需改 Cache 的内容,而不立即写入主存,只有当此块被换出时才写回主存。采用这种策略时,每个 Cache 行必须设置一个标志位(脏位),以反映此块是否被 CPU 修改过。

Cache 写未命中的处理方法

(1)写分配法

加载主存中的块到 Cache 中,然后更新这个 Cache 块。写分配法通常与写回法一起使用。(更新 Cahce )

在这里插入图片描述

(2)非写分配法

只写入主存,不进行调块。非写分配法通常与全写法一起使用。(更新主存)

在这里插入图片描述
写缓冲(Write Buffer):为了减少全写法直接写入主存的时间损耗,在 Cahce 和主存之间增加一个写缓冲。CPU 同时写数据到 Cache 和写缓冲中,写缓冲再控制将内容写入主存。写缓冲是一个 FIFO 队列,写缓冲可以解决速度不匹配的问题。但若频繁写时,会使写缓冲饱和溢出。因此,结合两种模式,我们提出了含有两级 Cache 的系统。

含有两级 Cache 的系统

L1 Cache 对 L2 Cache 使用全写法,L2 Cache 对主存使用写回法,由于 L2 Cache 的存在,其访问速度大于主存,因此避免了因频繁写时造成的写缓冲饱和和溢出。

 

在这里插入图片描述

### 缓存替换算法策略 #### LRU (Least Recently Used) LRU 是一种常见的缓存替换策略,其核心思想是移除最近最少使用的数据项。每当有新的数据加入到缓存中时,如果缓存已满,则会淘汰最久未被访问的数据项。这种方法假设过去很少使用的对象在未来也很少会被使用。 ```python from collections import OrderedDict class LRUCache: def __init__(self, capacity: int): self.cache = OrderedDict() self.capacity = capacity def get(self, key: int) -> int: if key not in self.cache: return -1 value = self.cache.pop(key) self.cache[key] = value # Move accessed item to the end. return value def put(self, key: int, value: int) -> None: if key in self.cache: self.cache.pop(key) elif len(self.cache) >= self.capacity: self.cache.popitem(last=False) # Remove least recently used item. self.cache[key] = value ``` #### FIFO (First In First Out) FIFO 策略按照进入顺序来决定哪些项目应该被淘汰。最早放入缓存中的条目将是第一个被删除的对象。这种方式实现简单,但在某些情况下可能不是最优的选择,因为它不考虑项目的实际使用频率[^1]。 #### LFU (Least Frequently Used) LFU 考虑的是每个缓存项的使用频次。当需要腾出空间时,LFU 将优先清除那些较少被请求的内容。这有助于保持更常用的数据始终存在于缓存之中。 ```python import heapq from collections import defaultdict class Node: def __init__(self, freq=0, keys=None): self.freq = freq self.keys = set() if keys is None else keys def add_key(self, key): self.keys.add(key) def remove_key(self, key): self.keys.discard(key) class LFUCache: def __init__(self, capacity: int): self.key_to_val = {} self.key_to_freq_node = {} self.min_freq = 0 self.cap = capacity self.freq_map = {0: Node()} def _update_frequency(self, key): node = self.key_to_freq_node[key] next_freq = node.freq + 1 if next_freq not in self.freq_map: new_node = Node(next_freq) self.freq_map[next_freq] = new_node next_node = self.freq_map[next_freq] del self.key_to_freq_node[key] next_node.add_key(key) self.key_to_freq_node[key] = next_node if not node.keys and node.freq == self.min_freq: self.min_freq += 1 def get(self, key: int) -> int: if key not in self.key_to_val: return -1 val = self.key_to_val[key] self._update_frequency(key) return val def put(self, key: int, value: int) -> None: if self.cap <= 0: return if key in self.key_to_val: self.key_to_val[key] = value self._update_frequency(key) return if len(self.key_to_val) >= self.cap: min_freq_node = self.freq_map[self.min_freq] evict_key = list(min_freq_node.keys)[0] min_freq_node.remove_key(evict_key) del self.key_to_val[evict_key] del self.key_to_freq_node[evict_key] self.key_to_val[key] = value self.freq_map.setdefault(1, Node()).add_key(key) self.key_to_freq_node[key] = self.freq_map[1] self.min_freq = 1 ``` #### ARC (Adaptive Replacement Cache) ARC 是一种自适应缓存管理器,它能够动态调整两个不同部分之间的大小比例——一个是用于存储最近频繁访问过的页面;另一个则是用来保存较早之前曾被读取过但仍有可能再次用到的信息。通过这种机制,可以更好地平衡短期长期的需求变化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值