4.3、多体交叉存储器、Cache的基本原理、相联存储器、 Cache地址映射与变换方法
4.3、多体交叉存储器、Cache的基本原理、相联存储器、 Cache地址映射与变换方法大家好我是你们的技术博主。今天我们来聊一聊计算机体系结构中几个非常重要的概念多体交叉存储器、Cache、相联存储器以及它们之间的地址映射与变换方法。这些内容看似复杂但如果我们用生活中的例子来类比其实非常容易理解。## 多体交叉存储器让数据“并行”起来先来说说多体交叉存储器。想象一下你有一个大图书馆里面有很多书架。如果你每次只能从一个书架上取书效率会很低。但如果多个书架同时开放你就能同时从不同书架上取书速度自然就快了。多体交叉存储器的思想与此类似。它将内存划分为多个独立的“体”bank每个体都有自己的数据总线和地址总线。当CPU需要连续访问内存地址时这些地址会被分散到不同的体中从而实现并行访问。常见的交叉方式有低位交叉和高位交叉两种。### 低位交叉示例假设我们有4个体Bank0~Bank3每个体有4个单元。低位交叉的地址映射规则是地址的低2位决定体号高地址决定体内偏移。例如地址0x00、0x01、0x02、0x03分别映射到Bank0、Bank1、Bank2、Bank3的第一个单元。这种设计特别适合连续地址的访问比如数组遍历。下面我们用Python模拟一下这种交叉存储器的行为pythonclass LowInterleavedMemory: def __init__(self, num_banks4, bank_size4): self.num_banks num_banks self.bank_size bank_size # 初始化每个体每个体是一个列表 self.banks [[0] * bank_size for _ in range(num_banks)] def addr_to_bank_and_offset(self, address): # 低位交叉地址的低2位决定体号 bank_id address % self.num_banks offset address // self.num_banks return bank_id, offset def write(self, address, data): bank_id, offset self.addr_to_bank_and_offset(address) if offset self.bank_size: self.banks[bank_id][offset] data else: raise IndexError(地址越界) def read(self, address): bank_id, offset self.addr_to_bank_and_offset(address) if offset self.bank_size: return self.banks[bank_id][offset] else: raise IndexError(地址越界)# 测试mem LowInterleavedMemory()mem.write(0x00, 100) # 写入Bank0偏移0mem.write(0x01, 200) # 写入Bank1偏移0mem.write(0x04, 300) # 写入Bank0偏移1因为0x04 % 4 0, 0x04 // 4 1print(f读取地址0x00: {mem.read(0x00)}) # 输出100print(f读取地址0x01: {mem.read(0x01)}) # 输出200print(f读取地址0x04: {mem.read(0x04)}) # 输出300## Cache的基本原理用“小本本”记录常用信息Cache缓存是计算机系统中一个高速但容量较小的存储器它的存在是为了解决CPU与主存速度不匹配的问题。你可以把Cache想象成你的随身小本本而主存是一个大图书馆。当你需要频繁查询某个信息时你会先在小本本上找如果找到了命中直接使用如果没找到未命中再去图书馆查并顺便把这条信息记在小本本上方便下次使用。Cache的基本工作流程是1. CPU发出内存访问请求2. 检查Cache中是否有该数据命中/未命中3. 如果命中直接返回数据4. 如果未命中从主存读取数据同时将数据写入Cache可能替换旧数据## 相联存储器让查找变得“智能”相联存储器Content-Addressable Memory, CAM是一种特殊的存储器它不是按地址访问而是按内容访问。你可以把它想象成一个“智能”的通讯录你不需要知道某个人的页码只需要输入名字它就能直接返回电话号码。在Cache中相联存储器被用来实现“标签”Tag的查找。当CPU访问某个地址时Cache会提取地址的标签部分然后与所有Cache行的标签同时进行比较并行比较从而快速判断是否命中。## Cache地址映射与变换方法Cache地址映射就是把主存地址映射到Cache中的某个位置。常见的映射方法有直接映射、全相联映射、组相联映射。### 直接映射直接映射就像给每个学生分配固定的座位每个主存块只能映射到Cache中唯一的一个位置。优点是实现简单缺点是容易产生冲突。### 全相联映射全相联映射就像自由入座每个主存块可以映射到Cache中的任意位置。优点是灵活冲突少缺点是硬件实现复杂。### 组相联映射组相联映射是前两者的折中把Cache分成若干组每个主存块可以映射到组内的任意位置。这就像电影院分区域每个区域内的座位可以自由选择但区域是固定的。下面我们用Python模拟一个直接映射Cache的实现pythonclass DirectMappedCache: def __init__(self, cache_size8, block_size1): self.cache_size cache_size # Cache行数 self.block_size block_size # 每个块大小这里简化成1个字 # 每个Cache行包含有效位、标签和数据 self.valid [False] * cache_size self.tags [0] * cache_size self.data [0] * cache_size def access(self, address): # 假设地址是字节地址我们按字访问每个字4字节 word_addr address // 4 # 直接映射用地址的低位作为Cache索引 index word_addr % self.cache_size tag word_addr // self.cache_size if self.valid[index] and self.tags[index] tag: # 命中 print(fCache命中地址{hex(address)}的数据为{self.data[index]}) return self.data[index] else: # 未命中从主存读取这里模拟主存数据 data_from_memory word_addr * 10 # 模拟主存数据 self.valid[index] True self.tags[index] tag self.data[index] data_from_memory print(fCache未命中从主存读取地址{hex(address)}的数据为{data_from_memory}) return data_from_memory# 测试cache DirectMappedCache()cache.access(0x00) # 未命中cache.access(0x10) # 另一个地址可能映射到不同行cache.access(0x00) # 命中### 地址变换过程无论采用哪种映射方式地址变换的流程都类似1. CPU发出地址后Cache控制器提取出标签、索引和块内偏移2. 根据索引找到对应的Cache行3. 比较标签是否匹配同时检查有效位4. 如果匹配且有效则命中根据块内偏移取出数据5. 否则未命中从主存读取数据并替换## 总结今天我们一起学习了计算机存储体系中的几个核心概念-多体交叉存储器通过并行访问多个存储体来提高数据传输带宽特别适合连续地址访问-Cache利用局部性原理通过存储最近使用的数据来加速CPU访问-相联存储器支持按内容查找是实现Cache标签匹配的关键技术-Cache地址映射决定了主存块与Cache行之间的对应关系直接映射、全相联映射和组相联映射各有优缺点这些概念虽然看起来复杂但它们都是为了解决同一个问题如何让计算机更快地访问数据。多体交叉存储器和Cache从不同角度提升了存储系统的性能而相联存储器则为快速查找提供了硬件支持。在实际的计算机系统中这些技术往往是组合使用的。比如现代CPU的L1 Cache通常采用组相联映射而多体交叉技术则被用于内存控制器中。理解这些原理对于我们编写高效的代码、优化程序性能非常有帮助。希望今天的分享对你有用如果你有任何疑问欢迎在评论区留言讨论。