当我们对各组件有了认识之后,那么我们在认识了CPU直接去访问内存的时候,需要申请总线控制权,而且一个8G的内存我们需要访问的地址也许就高达2的30次方,一次寻址访问拿到数据可能就要近百ns,而在CPU主频普遍高于3GHz的今天,内存无疑成为了拖累CPU的主要部件,而速率较快的SRAM又造价昂贵,所以早在一开始,内存速率开始拖累CPU的时候,就引入了高速缓存的机制。

什么是高速缓存?

我们在购买电脑时,通常查看参数时除了注意CPU的主频及核心数量,也会注意到有个缓存数量和缓存大小,一般分为L1,L2,L3缓存,以下图为例,分别为i7-10700F(左)和i5-10400F,两者价格相差了将近一倍,除了CPU核心数量跟多以外,还有智能高速缓存大小带来的价格差异,智能不智能咱不知道,但是很快很贵就对了。下图中的16MB和12MB就分别代表L3级缓存的大小,而通常大小L1<L2<L3的。

缓存SRAM造价昂贵,所以通常不会太大,但是却带来了巨大的提升,为了弥补两者之间的性能差异,我们能真实地把 CPU 的性能提升用起来,而不是让它在那儿空转,我们在现代 CPU 中引入了高速缓存。

内存中的指令、数据,会被加载到 L1-L3 Cache 中,而不是直接由 CPU 访问内存去拿。在 95% 的情况下,CPU 都只需要访问 L1-L3 Cache,从里面读取指令和数据,而无需访问内存。

缓存的理论支持:局部性原理

什么是局部性原理,做过生产开发或者用过Redis的应该知道,Redis就是主要拿来做缓存使用的,我们会缓存热点数据,下次再请求这些数据就不会去访问数据库了而是直接从缓存中获取,直接返回,这就是局部性原理中的时间局部性。

局部性原理包括时间局部性和空间局部性,在漫长的计算机发展过程中,开发人员发现,当一个数据被访问,那么短时间内这个数据再次被访问的概率很大,并且与他相邻的数据也会很快被访问,所以我们认为CPU会在短时间内集中访问一个区域内的数据,前者就是时间局部性原理,后者就是空间局部性原理。

认识字与字块:为了了解缓存是如何工作的我们需要先了解字与字块。

字节:字节是CPU寻址的最小单位,1字节等于8比特,也就是1byte=8bit,常用大B来表示。

字:是指存放在一个存储单元中的二进制代码组合,一个64位CPU,一个字的大小就是8byte

字块:存储在连续的存储单元中而被看作是一个单元的一组字节,64位CPU中这个字块可能是64byte,也就是8个字组成了一个字块。

那么Cache 的数据结构和读取过程是什么样的?

缓存的加载都是以字块为单位进行加载的,我们其实需要的是内存中的数据,那么缓存小内存大我们如何通过缓存找到我们想要的数据并且能够保证就是能跟内存里对应起来呢?

下面就来说说缓存的映射方式:

①:直接映射

以字块为单位将内存和缓存分割为数组,内存向缓存形成多对一的直接映射关系,内存中的一个字块能够映射到缓存中的索引是确定的,如21 号内存块内容在缓存块中的话,它一定在 5 号缓存块(21 mod 8 = 5)中。

但是这种映射又重新带来一种问题,图中5,13,21,29都能映射到缓存5上,我们怎么确定我要21的时候拿到的不是其他呢?

通常我们会把缓存块的数量设置成 2 的 N 次方,那么内存的字块数量也一定是缓存的二次方倍,如8 个缓存字块,就是 2 的 3 次方,32个内存字块就是 2 的 5 次方,我们在通过内存地址的获取缓存数据时候,只需要拿到段地址的低三位,就能确定缓存索引,再根据字块中的偏移量就能拿到唯一对应的字节,道理就是这么个道理。

那这个字是不是我们想要的,就需要引入另一个概念"组标记"

这个组标记会记录,当前缓存块内存储的数据对应的内存块,而缓存块本身的地址表示访问地址的低 N 位。就像上面的例子,21 的低 3 位 101,缓存块本身的地址已经涵盖了对应的信息、对应的组标记,我们只需要记录 21 剩余的高 2 位的信息,也就是 10 就可以了。

除了组标记信息之外,缓存块中还有两个数据。一个自然是从主内存中加载来的实际存放的数据,另一个是有效位用于存放缓存块中的数据是否有效的。如果有效位是 0,无论其中的组标记和 实际的数据内容是什么,CPU 都不会管这些数据,而要直接访问内存,重新加载数据。

重点来了,整体进行举例,比如一个64位的CPU,内存地址线宽度为40位,也就是说一个内存地址可以有40位,假设一个字块有64B,即64字节,内存大小为8G,缓存大小为8M。

由于内存大小为8G,即2的33次方字节,则最少需要33位地址可确定唯一字节。其中64B为一个字块,想要确定唯一字节需要6位地址,即2的6次方,所以偏移量需要6位;缓存大小是8M,即2的23次方字节,但是又因为一个字块是64B,所以缓存行数是2的23次方除以2的6次方,所以需要17位来确定唯一字块,即索引位数为17;缓存8M和内存8G相差2的10次方倍,所以组标记需要10位,高位补0。

所以一个内存地址的访问,就会经历这样 4 个步骤:

1.根据内存地址中段地址(字块地址为段地址)的低位,计算在 缓存中的索引;

2.判断有效位,确认缓存中的数据是有效的;

3.对比内存访问地址的高位,和缓存中的组标记,确认缓存中的数据就是我们要访问的内存数据

4.根据内存地址的 偏移量,从字块中读取希望读取到的字节。

如果在 2、3 这两个步骤中,CPU 发现,缓存中的数据并不是要访问的内存地址的数据,那 CPU 就会访问内存,并把对应的 内存中的数据字块更新到对应的缓存中,同时更新对应的有效位和组标记的数据。

②全相连映射

全相连映射方式比较灵活,主存的各块可以映射到缓存的任一块中,缓存的利用率高,字块冲突概率低,只要淘汰缓存中的某一块,即可调入主存的任一块。但是,由于缓存比较电路的设计和实现比较困难,这种方式只适合于小容量缓存采用。

③组相联映射

组相连映射其实就是直接映射和全相连映射取了一个中间值,内存和缓存按照统一大小进行分组,组间采用直接映射,组内采用全相联映射,也就是说组大小等于缓存大小那就是全相连,组大小等于字块大小那就是直接映射。

高速缓存的替换策略

  什么是缓存替换策略呢?就是当高速缓存中没有数据时,需要从主存中载入所需要的数据,但是缓存有可能已经满了,此时就要启动替换策略,也就是满了我要换谁。

高速缓存中常见的替换策略:

  • 随机算法:看谁不顺眼换谁
  • 先进先出算法(FIFO):谁先进来的谁先走
  • 最不经常使用算法(LFU):有空间会记录字块的使用频率,最不经常使用的会被淘汰。
  • 最近最少使用算法(LRU):优先淘汰一段时间内没有使用的字快,具体的实现方式可能是一个双向链表,数据每被访问一次就会被替换到链表表头,淘汰总是淘汰链表的末尾。

拓展重点:volatile关键字是如何实现内存可见性的?

Java的相关开发人员一定绕不开多线程,那么多线程一定绕不开volatile关键字。其实内存可见性的困扰一开始可能是没有的,他的来源其实是多核CPU的出现,每个核心都有自己的缓存(L1,L2是在核心里边的),那么我改了你不知道问题就出现了。

volatile 关键字究竟代表什么含义呢?它会确保我们对于这个变量的读取和写入,都一定会同步到主内存里,而不是从 Cache 里面读取,这样就不会出现脏读的情况。

使用多核多缓存那么必然要面临缓存的一致性问题,那么我们就必须要考虑两个问题,一个是告知,也就是我一个核心改了,其他核心要知道才行,第二个就是顺序,也就是事务的串行化,其他核心不止应该知道,更应该按修改顺序知道,并且按顺序加载,防止出现因为接收告知顺序的不同最后结果也不同。所以核心和核心之间应该有一条专门的总线,然后通过总线广播给所有的 CPU 核心。

基于这种广播有人开发出了一种缓存一致性协议:MESI

MESI 协议,是一种叫作写失效(Write Invalidate)的协议。在写失效协议里,只有一个 CPU 核心负责写入数据,其他的核心,只是同步读取到这个写入(参考主从复制)。在这个 CPU 核心写入 Cache 之后,它会去广播一个“失效”请求告诉所有其他的 CPU 核心。

MESI 协议的由来呢,来自于我们对 缓存字块的四个不同的标记,分别是:

M:代表已修改(Modified):数据已经被修改,这是个脏数据

E:代表独占(Exclusive):数据没问题,而且跟别的核心没关系,我可以随意修改

S:代表共享(Shared):各个核心共享,改之前得先告诉其他核心

I:代表已失效(Invalidated):数据已失效,丢弃,从主内存拿就行

在独占状态下的数据,如果收到了一个来自于总线的读取对应缓存的请求,它就会变成共享状态。而在共享状态下,因为同样的数据在多个 CPU 核心的 Cache 里都有。所以,当我们想要更新 Cache 里面的数据的时候,不能直接修改,而是要先向所有的其他 CPU 核心广播一个请求,要求先把其他 CPU 核心里面的缓存字块,都变成无效的状态,然后再更新当前 Cache 里面的数据。那么独占有没有让你想到ThreadLocal呢?

计算机组成原理(四)-CPU的高速缓存相关推荐

  1. 计算机组成原理之CPU以及高速缓存

    一 CPU组成结构 CPU主要包括四个组成部分,控制器.运算器.寄存器.时钟. 1.1控制单元 控制单元主要包括取指令.分析指令和执行指令以及对返回的结果进行时序控制.它主要使用到的寄存器包括IR(指 ...

  2. 计算机组成原理试题 t4,计算机组成原理(四版)本科生试题库整理附答案

    <计算机组成原理(四版)本科生试题库整理附答案>由会员分享,可在线阅读,更多相关<计算机组成原理(四版)本科生试题库整理附答案(5页珍藏版)>请在人人文库网上搜索. 1.29 ...

  3. 深入浅出计算机组成原理学习笔记:高速缓存(下)-你确定你的数据更新了么?(第38讲)...

    在我工作的十几年里,写了很多Java的程序.同时,我也面试过大量的Java工程师.对于一些表示自己深入了解和擅长多线程的同学, 我经常会问这样一个面试题:" volatile这个关键字有什么 ...

  4. 【计算机组成原理】CPU:单周期数据通路(MIPS)

    寄存器传送语言RTL 1)R(r)表示寄存器r的内容 2)M(address)表示主存储器地址address的内容 3)传输方向"←"表示,从右向左传输 4)程序计数器PC的内容直 ...

  5. 计算机组成原理 启航教育,2021计算机考研:计算机组成原理知识点CPU的功能和基本结构...

    启航教育小编为大家整理了关于"2021考研:计算机组成原理知识点CPU的功能和基本结构"的相关内容,希望可以帮助到大家,祝大家考上自己理想的院校 CPU的功能和基本结构 CPU主要 ...

  6. 【计算机组成原理】CPU如何区分指令和数据

    [计算机组成原理]CPU如何区分指令和数据 指令周期 题目 指令和数据放在内存中,对于CPU而言,我们要怎么区分里面是数据还是指令呢? 冯 · 诺依曼计算机中指令和数据均以二进制形式存放在存储器中,C ...

  7. 计算机组成原理网易云,计算机组成原理之CPU

    课程概况 哈尔滨工业大学"计算机组成原理"课程是国家级精品课程,以国家级教学名师唐朔飞教授编写的"十二五"规划教材为基础,将教学课件.学习指导与习题解答.试题库 ...

  8. 计算机组成原理——8086 CPU寄存器

    本篇文章转载自 https://www.cnblogs.com/BoyXiao/archive/2010/11/20/1882716.html 结合文章做了一些小修改,使文章更完整. 1 总线 只是想 ...

  9. 深入浅出计算机组成原理 通过CPU主频看性能(自我提升第8天)

    希望大家关注菜鸟,不然后期的文章,各位可能无法及时看到 文章目录 深入浅出计算机组成原理 1.计算机性能的两个指标 2.计算机的计时单位: CPU时钟 大家了解了上面的知识点,那接下来就是两者结合的高 ...

最新文章

  1. 普通用户 fork报错 fork: retry: No child processes 解决方法
  2. CVPR 2022 3月7日论文速递(17 篇打包下载)涵盖 3D 目标检测、医学影像、图像去模糊、车道线检测等方向
  3. 了解React Native中的不同JavaScript环境
  4. FinTech:一个单体系统足以撑起银行持续交付全球大项目
  5. 关于轻重边及树链剖分该怎么写...
  6. 手势UIGestureRecognizer
  7. 业务中台管理系统、业务中台架构、接口类服务、模型类服务、界面类服务、组件类服务、服务架构、中后台、服务审核、AI服务、位置服务、行业场景服务、企业中台、接口配置、模型配置、数据处理、结构化数据、数据源
  8. 深度数据对接 链接服务器 数据传输
  9. 餐饮管理系统开发源码
  10. 一道经典的C++题,关于分钱的问题,适合新手阅读(黑客X档案论坛题目)
  11. 基于Unity的极乐净土/others MMD动画制作
  12. 设计心理学1_日常的设计 读后感
  13. 小米笔记本bios版本大全_聊一款被“差别对待”的笔记本电脑
  14. TableView图片闪动的问题
  15. MATLAB将csv文件转换成mat文件
  16. SAP MM库存盘点流程
  17. 4-2. 打印九九口诀表
  18. 如何注册我的世界服务器账号密码,我的世界电脑服务器怎么注册登录密码
  19. rs232读取智能电表_跟大家聊一聊智能电表上的铭牌认识,和电表的防窃电。
  20. linux亦步亦趋(19)文件管理之VI配置全局化

热门文章

  1. [游戏开发]手机发热问题总结
  2. 三个对腰痛很有效的动作
  3. 群晖 建立文件禁止访问_在设计系统中建立可访问性
  4. RxJava2.X 源码分析 一
  5. 网易极客战记-KITHGARD地牢--虚幻干扰
  6. android 椭圆轨迹旋转,Android 倾斜椭圆绘制方法
  7. 华为机试真题 Java 实现【Excel单元格数值统计】【2022.11 Q4】
  8. switch别致源码
  9. oracle未明确定义列
  10. C++ 中的分号 语句块