问题
- 在cache 中访问的内存地址为何会带有 cache 相关的信息 ,动机是什么?
前言
平时只知道cpu 到内存之间还有一层 cache , CPU 要去主存找一个数据 ,第一反应肯定是到先到 cache 中找 ,如果找不到再去主存中去找, 要是找到了,直接就返回了 . 上面的过程实际就是通过 主存地址 这个东西来判断数据是否存在cache 中 . 其实主存地址在不同的地方是长不一样的, 比如在 cache 里面为了去找一下 cache 有没有 ,那么是长这样的, 假如是去主存找 ,那么我首先得到页表找 , 那么主存地址又是长另外一个样子 , 也就是说通过 主存地址 我们可以达到不同的目的 , 这一点需要记住 !
cache 在哪
下图可以看到 cache 在寄存器和内存的中间 ,起到缓存的作用. 对内存进行缓存
高速缓存如何工作
既然是对内存进行缓存, cache 的空间小, 内存的容量大, 可以看到缓存的单位是 Block (内存块) , 内存块内部其实还可以继续细分 . cache 与内存之间的映射方法有三种
第一种方式 : 直接映射
我们首先对内存块进行编号, 0号内存块( 0 块) , 1号内存块( 1 块 ), 2号内存块, 3号内存块 ...cache的记录空间称为条数(行或者槽) ,如下图 , 对 16 取余数, 1块 17块 33块 ..
, 2块 18块 34块...
分到另外一个槽 . 分配过程假如冲突了就会发生替代, 例如我们的槽中原本放着 1号内存块, 后来给 17号内存块替代了.
那我们看到 Cache 中这个表格的 0 号槽到底有没有放数据啊 ,如果放了数据那么放的是内存的第几块内存呢?? 所以这一定有两个标识 :
- 有无标识 v : 是否cache 里面放了数据没有的标识
- tag : 标识槽位放的是第几个块群的数据 , 例如 cache的 1号槽位 , 放有数据 ,并且tag 是 1 那么我们就知道了 , 1号槽放的是内存第 17块内存
搞懂了上面的内存的块是如何放到 cache 里面去的了. 我们再来看一下 CPU 发过来的主存地址是如何先去找 cache , 然后看看是否命中的 , CPU 发过来的地址有 20位 ,这 20位包括了
主存标识 + Cache 槽号 + 块内地址
,其中 :
-
主存标识 : 就是哪一个块群
-
Cache 槽号 : Cache 哪一个槽号的
-
块内地址 : 内存块中还再细分的
例如我要找的地址是
0220CH
, 变成二进制就是0000 0010 0010 0000 1100B
, 我首先到0001
(Cache 槽号) 槽位看一下是否存在数据, 假如是第一次 , cache 肯定是没数据的 , cache 没数据肯定需要将数据加载到内存中去 , 然后内存的数据再copy 到 cache 中去 , 那么是内存的第几块内存啊 ? 看一下前 7位 ---0000 001
第一块群 , 第一块群放在 cache 的 1号槽 ,那只能是17块内存啦 !经过了这么一顿操作 , 内存的 17块内存已经被放在内存和 cache 中去了 ,第二次 ,我同样访问 地址是
0220CH
, 同样我先看Cache 槽号 , 里面已经有数据了 ! (v标识表示有数据 ), 再比对一下是哪个块群 , 是 cache 的 1号槽 的第一块群 ( tag 也比中了!! ), 于是我就不再前往内存中拿数据了 , 因为 cache 中有我想要的数据了
直接映射下的Cache 的标志位
这里的 tag 和 v 就是我们前面所说的标志位
第一个位表示是否存在cache 中, 有效无效 , tag 则是当前 cache 里的 data 取自哪个块群的 (因为有可能来自不同的块群)
直接映射的另外一个例子
对比的时候先拿内存地址
中的Cache 槽号
找到对应的 Cache记录, 然后再对比该记录中的 tag 是不是自己的块群, 要是是的话那么继续比对是否有效有效标识, 要是这都能对上说明内存块存在 Cache 中呀!
直接映射的特点
我们前面也看到了每个块对应于 cache 哪个位置是固定的, 那假如有几个块主存电脑用的比较频繁, 但是都是同一个槽号的,比如 0号槽位的 0 ,16,32块内存 , 那岂不是得频繁的换进换出 ?? 是的 !!
第二种方式 : 全相联映射Cache
全相联映射的映射是这样的, 只要有空的位置就往里缓存 , 哈哈哈 , 反正有位置就放就完事了 ,没位置就根据一定的规则把某些放太久的换出来,可以想象得到这肯定也有问题 ,比如
- CPU 给个主存地址 ,我也不知道在不在 cache 槽里, 那么我就只能一个个对面,直到对比中了
- 使用频繁的块内存肯定老是在槽里 ,那么使用频率低的肯定都给挤出槽了
这种方式就有意思了, CPU给过来的主存地址就只有两部分的组成了
- 标记/主存块号
- 块内地址
比如CPU 传过来 01E0CH
, 转化为二进制就是 0000 0001 1110 0000 1100B
, 前 11位表示的是15块主存 , 我就那个 15 去 cache 对比一下 tag , 看一下 tag 里面有没有 15 ,有的话并且数据标识表示存在数据 ,那么就是比中了 ,反之没比中 !
第三种方式 : 组相联映射
组相联映射
结合直接映射
和全相联映射
的特点 , 你看我们上面用全相联映射的缺点是他喵的, 所有的主存块乱放, 我他喵一个个对比 ,比到什么时候嘛 , 于是组相联映射
先将 cache 的容量进行分组 , 对应的内存块只能放到对应的组呢 ,然后一组又有很多个空间, 这时候内存块就可以随便放 , 找的时候也是先找到对应的是哪一个组的,再在对应的组内进行比对
这个方法的主存地址, 第一部分,标记
放的是位于内存中哪个块群, Cache索引
是位于Cache哪个cache组 , 块内地址
这个就不用解释了
缺失率和关联度
关联度有点像查找命中的过程中扫描的条数
其他
关于虚拟地址 (重要)
之前以为虚拟地址是一成不变的,其实这就是一个误区, 这篇文章 cache 算是CPU 访问数据的开端 , 认真想想, 对于内存来说, cache 是内存的缓存, 而对于磁盘来说 ,主存又是
磁盘的缓存, 我们学习这篇文章的时候 , 会发现内存地址
放着关于 cache 目的就是访问的时候,先到 cache 去找 ,我们后面还会学到页表和 TLB , TLB 是页表的缓存, 所以可想而知访问页表的内存地址
也会有关于TLB 相关的信息 . 最后放上一张关于访问内存的流转图 ! (重要)
同样的道理我们到时候也会看到在不同阶段 ,内存地址
会不一样.
参考
- <袁春风-操作系统>