[408] cache与主存的映射--地址结构

本文介绍了计算机存储中地址的概念,包括按比特和字节编址,以及块的概念。解释了Cache和主存的块大小与地址关系,讨论了全相联、直接和组相连映射的不同地址划分方式,并探讨了Cache容量和Cache总容量的计算方法。

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

涉及:
	基本理解 (防止误解映射规则
	cache 与 主存 的 "地址"构成
	主存块、cache块
	cache容量、cache的总容量
	有关计算的一些刁难名词
	
不涉及:
	cache 与 主存映射规则

基本理解:
 首先我们需要明确的是我们之后针对的位数都是针对的 地址. 与实际的存储的 (01) 二进制无关. 地址与存储的实际数据是两个不同的概念. 我们的映射规则是建立在地址上的.

 “” 的概念其实 和 按字节编址 是相似的.

设 我们能够存储 232bit2^{32}bit232bit 的二进制位.
 ① 如果是按 比特 编址, 那么会存在如下地址
0000 ... ... 0000 0000⏟32∼1111 ... ... 1111 1111⏟32\underbrace{0000 \: ... \: ... \: 0000 \: 0000}_{32} \sim \underbrace{1111 \: ... \: ... \: 1111 \: 1111}_{32}320000......00000000321111......11111111
 ② 如果按 字节 (one B = eight bit) 编址:
  2322^{32}232 可以分成 (232/23)(2^{32}/2^{3})(232/23) 个部分, 即 (32−3)(32-3)(323)
0000 ... ... 0000 0000⏟29000⏟3\underbrace{0000 \: ... \: ... \: 0000 \: 0000}_{29}\underbrace{000}_{3}290000......000000003000
  那么这 292929 位就是表示 888bitbitbit 一组的地址了.
 
 ③ 同理 “块” 是一样的, 假设一个块的大小是 16bit16 bit16bit
0000 ... ... 0000 0000⏟28000⏟4 块内地址\underbrace{0000 \: ... \: ... \: 0000 \: 0000}_{28}\underbrace{000}_{4 \: 块内地址}280000......000000004块内地址000
  这前 282828 位就是用来划分块的了, 后 444 位就是所谓的的块内地址

注: 地址在计算机存储中是观测不到的.


cache 与 主存的 " 地址 " 构成:
 与其说是地址构成, 不如说成是 地址能分成哪些部分.
注: cachecachecache 的地址是不包括 标记项. 标记项对于 cachecachecache 来说更像是为了方便而方便, 而在原地址上添加的.

经过了上面关于分块的解释,我们就很容易理解地址的划分:
① 全相联映射:
在这里插入图片描述
如我们上面假设, 那么 块内地址的位数为: 444, 用来表示 "块地址"的位数为: 282828.
 如果是对 cachecachecache 地址结构的求解, 那么这 282828 位表示的是 cachecachecache 行号的位数.

② 直接映射:
在这里插入图片描述

如上面我们假设的块大小, 那么块内地址位数为: 444, 标记位 与 cachecachecache 行号的位数总和为: 28.
0000 ... ... 0000 0000⏟28 "块地址"000⏟4块内地址\underbrace{0000 \: ... \: ... \: 0000 \: 0000}_{28\:"块地址"}\underbrace{000}_{4块内地址}28"块地址"0000......000000004块内地址000
 在原 282828 位的基础上标记位cachecachecache行号 的划分涉及到了 直接映射 的规则.  (你也可以理解为 “块地址” 是用 标记位 和 cachecachecache行号 表示的.
 
假设 cachecachecache282^828 行, 那么将如下映射: (有关 cachecachecache 行数的计算之后会涉及
228 % 282^{28} \: \% \: 2^{8}228%28
二进制运算规则
0000 ... ... 0000⏟20 0000 0000⏟8 余数\underbrace{0000 \: ... \: ... \: 0000}_{20} \: \underbrace{0000 \: 0000}_{8 \: 余数}200000......00008余数00000000
所以 “块地址” 又可以划分为 “标记位” 与 “cache行号cache行号cache行号”.

③ 组相连映射:
在这里插入图片描述
如果理解了 直接映射 的行号划分, 那么组号是一样的.

假设 cachecachecache888 组, 那么将如下映射: (有关 cachecachecache 行数的计算之后会涉及
228 % 232^{28} \: \% \: 2^{3}228%23
二进制运算规则
0000 ... ... 0000⏟25 000⏟3 余数\underbrace{0000 \: ... \: ... \: 0000}_{25} \: \underbrace{000}_{3 \: 余数}250000......00003余数000
所以 “块地址” 又可以划分为 “标记位” 与 “cache组号cache组号cache组号”.

主存块、cachecachecache
 因为这两个"块"中存储的数据是一样的, 所以 主存块的大小 必然要等于 cachecachecache块大小.

那假设 主存块的大小为 323232 字节, 我们可以知道些什么能?
 其实我们上面已经求过了 →\rightarrow 块内地址的位数. 我们试着求一下
32B=25B32 B = 2^5B32B=25B 那么 块内地址就是 555 位 ( 如果没说明按什么方式编址, 那么默认按字节编址.
解读: 存储块的大小 →\rightarrow 以多大的空间分块.

cachecachecache容量、cachecachecache总容量
 cachecachecache容量 = cachecachecache行数 ×\times× 存储块大小
 上面这个公式是不是相当的眼熟:
cache地址结构{cache行号位块内地址位 cache地址结构 \begin{cases} cache行号位\\ 块内地址位 \end{cases} cache地址结构{cache行号位块内地址位
那么 ① 式就可以转换成:
cache容量=2行号位数×2块内地址位数×2编码位数 cache容量 = 2^{行号位数} \times 2^{块内地址位数} \times 2^{编码位数} cache容量=2行号位数×2块内地址位数×2编码位数注: 为什么要乘以编码位数在 基本理解 中已经求过了. 整个容量的位数去除编码位数才是地址表示的位数.

假设 cachecachecache容量大小为 64KB64KB64KB, 存储块大小为 32B32B32B, 按字节编址 (3位)(3位)(3).

64KB→216∗23→cache64KB \rightarrow 2^{16}*2^{3} \rightarrow cache64KB21623cache地址(19−3)=16(19-3)=16(193)=16
32B→25∗23→块内地址(8−3)=5位32B \rightarrow 2^{5}*2^{3} \rightarrow 块内地址(8-3)=5位32B2523块内地址(83)=5

利用公式: cachecachecache行数 = cache容量 / 存储块大小cache容量 \: / \: 存储块大小cache容量/存储块大小.
64KB / 32B=21164KB \: / \: 32B = 2^{11}64KB/32B=211 所以 cachecachecache 行位数为 111111.

 cachecachecache总容量 = (各种标指位的位数 +++ 标记位数 +++ 块内地址位数) ×\times× 行数
注意这里括号内的位数并不包括 cachecachecache 的行位数. 这个就是规定. 记住就好了

有关计算
在这里插入图片描述

 ① 行长 (有时也称行大小 : 存储块大小
 ② cachecachecache有效容量 : cachecachecache 容量


-- over.

### 缓存主存映射的工作原理及实现 #### 1. 映射方式概述 缓存(Cache)是一种高速存储器,用于临时保存处理器频繁访问的数据副本。为了提高数据访问速度并减少延迟,缓存通过特定的映射策略来管理其主存之间的关系。常见的映射方式有三种:全相联映射、直接映射以及组相联映射。 #### 2. 全相联映射 (Fully Associative Mapping) 在这种映射方式下,任何主存块都可以被放置到缓存中的任意位置。这种方式提供了最大的灵活性,因为不需要固定的位置约束[^1]。然而,由于每次查找都需要对比整个缓存的内容,因此硬件开销较大,适合小型缓存设计。 ```python def fully_associative_mapping(main_memory_block, cache): for i in range(len(cache)): if not cache[i]['valid'] or main_memory_block['tag'] == cache[i]['tag']: cache[i]['data'] = main_memory_block['data'] cache[i]['tag'] = main_memory_block['tag'] cache[i]['valid'] = True break ``` #### 3. 直接映射 (Direct Mapping) 直接映射规定每一个主存块只能映射到缓存中唯一的一个位置。这种方法简化了硬件结构,降低了成本,但由于存在冲突的可能性,可能导致某些常用数据无法驻留在缓存中[^2]。 当访问内存时,会先计算出目标地址所在的行号,并将其定位至缓存对应行。随后验证该行标签是否匹配当前请求地址的标签部分,同时确认有效位为`1`。如果条件满足,则表示命中;否则发生未命中事件。 ```python def direct_mapping(address, cache_size, block_offset_bits): index = address >> block_offset_bits & ((cache_size // 2 ** block_offset_bits) - 1) tag = address >> (block_offset_bits + int(math.log2(cache_size))) hit = False if cache[index]['valid'] and cache[index]['tag'] == tag: hit = True return {'hit': hit, 'index': index} ``` #### 4. 组相联映射 (Set Associative Mapping) 这是一种折衷方案,在保持一定灵活性的同时兼顾性能和复杂度。具体来说,它将缓存划分为多个集合(set),每个集合内部采用类似于全相联的方式运作,而不同集合之间则遵循固定的分配规则[^3]。 例如,假设我们有一个两路组相联缓存(2-way set associative),那么对于某个给定的主存块而言,它可以放入两个可能的选择之一之中——这取决于它的索引(index)值所指向的具体分组(group)。 ```python def set_associative_mapping(address, associativity, num_sets, block_offset_bits): index = (address >> block_offset_bits) % num_sets tag = address >> (block_offset_bits + int(math.log2(num_sets))) hits = [] for way in range(associativity): entry = cache[index][way] if entry['valid'] and entry['tag'] == tag: hits.append(True) return any(hits), index ``` #### 总结 以上介绍了三种主要的缓存-主存映射机制及其基本操作流程。实际应用过程中需综合考虑系统需求、资源限制等因素选取最合适的配置形式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值