- 本篇文章是对王道考研的2021计算机组成原理学习笔记,希望对大家有所帮助。
三、存储系统
3.1 基本概念
知识总览:
![image-20210623232321106](https://i-blog.csdnimg.cn/blog_migrate/14b97640505cf62742082115bf9f1cf8.png)
1.存储器的层次结构
![image-20210623232503861](https://i-blog.csdnimg.cn/blog_migrate/c843265d4e243b47d80b3244a4956ab2.png)
主存——辅存:解决了主存容量不够的问题。
Cache——主存:解决了主存与CPU之间速度不匹配的问题。
![image-20210623232825208](https://i-blog.csdnimg.cn/blog_migrate/d2f532d02167d1267b0b27083c868338.png)
2.存储器的分类
(1)按层次进行分类
![image-20210623233313249](https://i-blog.csdnimg.cn/blog_migrate/66f8604457b7da1660566f90d0a3b20b.png)
(2)按传输介质进行分类
- 半导体:主存、Cache
- 磁表面存储器: 磁盘,磁带
- 光存储器
(3)按存取方式进行分类
- 相联存储器:可以按照内容检索到存储位置进行读写。
- 随机存取存储器(RAM):读写任何一个存储单元所需的时间都相同,与位置无关。(内存 )
- 顺序存取存储器(SAM):读写一个存储单元所需的时间取决于存储单元所在的位置。(磁带)
- 直接存取存储器(DAM):既有随机存取特性,也有顺序存取特性。先直接选取信息所在区域,然后按顺序方式进行存取。(机械硬盘)
顺序存取存储器和直接存取存储器都归为串行访问存储器(读取时间和数据位置有关)。
(4)按信息的可更改性进行分类
- 读写存储器:可读可写(如内存,硬盘等)
- 只读存储器:只能读,不能写(如电影使用的光碟)
(5)按信息的可保存性进行分类
- 易失性存储器:断电后数据消失(主存,Cache)
- 非易失性存储器:断电依然保存(磁盘、光盘)
- 破坏性读出:读出数据后要进行重写(如DRAM芯片)
- 非破坏性读出:读出数据后原数据没被破坏(如SRAM芯片、磁盘、光盘)
3.存储器的性能指标
- 存储容量:存储字数 x 存储字长(如 1M x 8位 )。
MAR反映存储字数,MDR反映了存储字长。
-
单位成本:每位价格 = 总成本/总容量(某条内存条价格为259,容量为8GB,则单位成本 = 259 / (8*8) )。
-
存储速度:数据传输率 = 数据的宽度/存储周期
-
存取时间:存取时间 + 恢复时间 = 存取周期,计算机进行一次读写操作后需要一段恢复时间才能进行下一次的读写操作。
-
主存带宽:就是上面的数据传输率,表示每秒从主存进出信息的最大数量,单位为字/秒,字节/秒,位/秒。
3.2主存储器
3.2.1主存储器的基本组成
知识总览:
![image-20210624001528956](https://i-blog.csdnimg.cn/blog_migrate/83f305a6c0f5d30238e2a55ae6495071.png)
(1)存储体
存储体由多个存储单元构成,每个存储单元由多个存储元构成。
存储元:能够存储一位比特。
![image-20210624002517073](https://i-blog.csdnimg.cn/blog_migrate/2d713c95c3c521b7278525e7ce1c13c5.png)
电容:存储电荷,有电压差表示比特1,无电压差表示比特0。
MOS管:一个电控开关,当输入电压到达某个阀值时,MOS管就可以接通,电容中的电荷就可以跑出来。(相当于一个电路的开关)
将多个存储元组合起来就构成了存储单元,同个存储单元的存储元共用一根MOS管。
将多个存储单元组合起来就构成了存储体。
(2)地址寄存器和数据寄存器
通过 译码器来选择哪一个存储单元进行读写。
并通过数据总线传送数据。
(3)控制电路:
控制电路控制着 MAR,译码器和MDR的数据处理。
同时存储芯片还需要对外提供 片选线,读选择线,写选择线。
片选线:芯片的总开关,低电平有效时表示选择了这块芯片进行工作了。
读选择线,写选择线:分别用来控制是读还是写。有时候会将这两根线合为一条,用低电平表示写,用高电平表示读。
(4)从总体上来看:
![image-20210624004544524](https://i-blog.csdnimg.cn/blog_migrate/a8b7f59f49096483a1eed24c3059cd98.png)
![image-20210624004842531](https://i-blog.csdnimg.cn/blog_migrate/29b4c43460a5b8a3bc524bf2ae7f3b6a.png)
这里也表明了片选线的作用,上述的内存条是由多个存储芯片构成,假设每个存储芯片为1GB,则这条内存条条就为8GB,在进行读写数据时,需要通过片选线来选取不同的存储芯片进行存储。
寻址:
![image-20210624010422947](https://i-blog.csdnimg.cn/blog_migrate/d5a8a52f0d65d3a02178618dcac1c6f6.png)
假设该存储体中的存储字长为4B,总容量为1KB,则存储单元为256个。
寻址方式可分为四种:
- 按字节寻址:则有1K个地址,需要10根地址线
- 按字寻址:则有256个地址,字节地址等于字地址乘于字长。
- 按半字寻址
- 按双字寻址
3.2.2 随机存取存储器RAM
知识总览:
![image-20210624194927812](https://i-blog.csdnimg.cn/blog_migrate/1eed95ccfe4a3f8f3b77fd60dc726f53.png)
RAM主要分为两种:
SRAM:静态RAM,用于Cache
DRAM:动态RAM,用于主存
1.存储元件不同导致的特性差异
DRAM芯片:使用栅极电容来存储信息
SRAM芯片:使用双稳态触发器来存储信息
(1)栅极电容:
![image-20210624201446831](https://i-blog.csdnimg.cn/blog_migrate/046bad07b474775139776a4df09175ad.png)
1:电容内存储了电荷
0:电容内未存储电荷
破坏性读出:电容放电后相当于电荷跑了出来,导致信息破坏,所以读出后需要有重写操作,也称为再生。这也是DRAM读写速度比SRAM慢的原因。
电容内的电荷只能维持2ms,即便不断电,2ms后信息也会消失。所以在2ms之内必须刷新一次,给电容充电。
每个存储元制造成本更低,集成度高,功耗低。
(2)双稳态触发器:
![image-20210624201746636](https://i-blog.csdnimg.cn/blog_migrate/26060d6930b02c42583d3c08eac02c5f.png)
1:A处为高电平并且B处为低电平
0:A处为低电平并且B处为高电平
非破坏性读出:读出数据后,触发器状态保持稳定,无需重写。读写速度更快。
只要不断电,触发器的状态就不会改变。
每个存储元制造成本更高,集成度低,功耗高。
2.DRAM的刷新
(1)多久刷新一次:一般为2ms
(2)每次刷新多少个存储单元:以行为单位,每次刷新一行存储单元。
存储器中存储单元的排列是由 行地址译码器 和 列地址译码器 共同选择。
![image-20210624204328703](https://i-blog.csdnimg.cn/blog_migrate/b86d149a365878306df226ba4c4ef25d.png)
如果只使用一个译码器来进行地址选择的话,那么8位地址需要使用 28=256 条选通线,而使用行地址译码器和列地址译码器共同工作的话,只需要 24+24=32 条选通线,也就是行译码器16条选通线,列译码器16条选通线。
(3)如何刷新:有硬件支持,读出一行的信息后重新写入,占1个读/写周期。
(4)什么时候进行刷新?
假设DRAM内部结构排列成 128x128 的形式,读/写周期为 0.5us ,则 2ms 内共有 2ms/0.5us=4000个 读/写周期。
于是刷新的时间选择可以有以下三种思路:
3.DRAM的地址线复用技术
由于DRAM存储容量较大,存储单元数目多,所需地址线也就比较多,为了简化硬件,采用地址线复用技术,行地址和列地址分成两次进行传送到译码器中。
![image-20210624211522648](https://i-blog.csdnimg.cn/blog_migrate/dae59a16d28d41ea675d9107ea254df1.png)
总结:
3.2.3 只读存储器ROM
![image-20210624211903579](https://i-blog.csdnimg.cn/blog_migrate/dc60d93c2d3be38feb83cf3380b7d5bb.png)
- ROM芯片虽然叫做“Read Only”,但是很多ROM也可以写。
- 闪存的写速度一般比读速度慢,因为写入之前需要先擦除。
- 事实上很多ROM也是具有随机存取的特性的。
3.2.4 主存储器和CPU的连接
![image-20210624214039285](https://i-blog.csdnimg.cn/blog_migrate/2770743366207bdf470d891431e2c3ac.png)
1.单块存储芯片与CPU的连接
![image-20210624222948187](https://i-blog.csdnimg.cn/blog_migrate/be7e366e4a47905b5406ef55f79a99ed.png)
假设有一块 8Kx1位 的存储芯片,说明此芯片需要 13根地址线,CPU有8个数据线和16根地址线,从上面可以看出,CPU每次只能传送1位数据到该芯片中,这会导致CPU的数据线没有得到充分利用,并且会有需要扩展主存容量的情况。
于是,就需要通过多个存储芯片的合理连接来扩展主存容量。
可以有两种方式:
- 位扩展:扩展存储单元的字长
- 字扩展:扩展存储单元的个数
2.多块存储芯片与CPU的连接
(1)位扩展:
![image-20210624224156942](https://i-blog.csdnimg.cn/blog_migrate/bb91a4d6aa7c307c8757dd1374861648.png)
如上图,将两片存储芯片进行连接,CPU地址总线A0~A12会一起发送给这两块芯片,而第二块芯片的数据线D0会和CPU的数据线D1进行相连。这样就扩展成了8Kx2位的存储器了。
同样,CPU中一共有D0~D7个数据线,因此可以总共连接8个图中所示的存储芯片,扩展成 8Kx8位的 存储器。
![image-20210624224658638](https://i-blog.csdnimg.cn/blog_migrate/2606bd16c438b49cc57f0a9925a32af3.png)
(2)字扩展:
字扩展可分为两种:
- 线选法
- 片选法
![image-20210624230816431](https://i-blog.csdnimg.cn/blog_migrate/d568c195d787931505a2c647c44e11ee.png)
如图中是一块 8Kx8位 的存储芯片,由于该芯片的存储单元字长等于CPU的数据总线数,因此不需要进行位扩展。而地址线并没有被完全利用到,因此可以考虑进行字扩展。
- 线选法:
![image-20210624230829234](https://i-blog.csdnimg.cn/blog_migrate/8f49a18b3bc018f719bf7c6cb2f332d5.png)
用专门的地址线作为片选线,进行选择某一块存储芯片。
如图中:A13为第一块存储芯片的片选线,A14为第二块存储芯片的片选线,当A13 A14分别为01或10时,代表选中了第一块存储芯片或第二块存储芯片,这样就能扩展存储单元的个数。
此时第一块存储芯片的最低地址为:01 0000 0000 0000,最高地址为 01 1111 1111 1111
第二块存储芯片的最低地址为:100 0000 0000 0000,最高地址为 101 1111 1111 1111
但是线选法有一个缺陷:A13和A14不能取00或者11,因为取00时会导致两快存储芯片都没有被选中,11会导致两块存储芯片都被选中。并且需要n个片选信号。
可以进行优化:
![image-20210624232229945](https://i-blog.csdnimg.cn/blog_migrate/55841230bf6c88fc3e88187b52e68404.png)
只通过A13和一个非门来进行选择。
此时第一块芯片的最低地址为10 0000 0000 0000,最高地址为11 1111 1111 1111
第二块芯片的最低地址为00 0000 0000 0000,最高地址为01 1111 1111 1111
- 片选法:
总结:
![image-20210624233026242](https://i-blog.csdnimg.cn/blog_migrate/edd07b5b03abe16606018893488af162.png)
(3)位扩展和字扩展 同时扩展
3.2.5 双端口RAM和多模块存储器
知识总览:
- 存取周期 = 存取时间 + 恢复时间
![image-20210625105008208](https://i-blog.csdnimg.cn/blog_migrate/844815a084215d3079fea9d7ff60f4da.png)
前面讲到,DRAM由于电容的特性,每次进行读操作后需要进行重写,也就是需要一定的恢复时间,导致DRAM的存取周期比较长,并且这个恢复时间往往还比存取时间长。
这样会引出以下两种问题:
-
对于现如今的计算机,很多都是具有多核CPU,那么不同的CPU访问主存时,后续的CPU是否需要等待这么长的恢复时间呢?
-
CPU的读写速度比主存快很多,主存恢复时间太长怎么办?
这两个问题分别对应接下来的内容:双端口RAM 和 多模块存储器。
1.双端口RAM
![image-20210625105611426](https://i-blog.csdnimg.cn/blog_migrate/b400d65126474e1b9547c0f24a3c104e.png)
**需要两组完全独立的数据线,地址线, 控制线。**CPU和RAM中也要有更复杂的控制电路。
两个端口对同一主存操作有以下4种情况:
当发生冲突时,会发出忙信号,有判断逻辑决定暂时关闭一个端口(即被延时),未被关闭的端口正常访问,被关闭的端口延长一个很短的时间断后再访问。
2.多模块存储器
(1)多体并行存储器:
图中每个方格表示一个存储单元。
高位交叉编址:每个存储体遍历完了之后再遍历下一个存储体。仅仅相当于扩容。
低位交叉编址:以横向方式遍历存储体,也就是每次都是遍历不同存储体的不同存储单元。这样,在读取其他存储体的存储单元时,之前读取过的存储单元可以利用这段时间进行恢复,达到一种并行的效果。
在模块数的选取上需要保证模块数 m >= T/r,这样才能保证存储体有足够的时间进行恢复。
(2)单体多字存储器:
![image-20210625113409932](https://i-blog.csdnimg.cn/blog_migrate/8b0d2d02ffd0d3685ab0b219ac3df411.png)
和多体并行存储器相反,单体多字存储器将多个存储体进行了合并,每次只能同时取m个字,不能单独取其中某个字,当某次读写的数据在不同行时,需要读入多余的信息。
3.应用
双通道内存:
原理:低位交叉编址的多体并行存储器。
3.3 Cache
3.3.1 Cache的基本概念和原理
知识总览:
![image-20210625145053543](https://i-blog.csdnimg.cn/blog_migrate/0536fbbe75440c3df278cdd9662a4b5e.png)
虽然 双端口RAM和多模块存储器已经提高了存储器的工作速度,但是和CPU的差距依然很大,于是就产生了缓存Cache,其价格更高,容量更低。
(1)工作原理:
![image-20210625144858180](https://i-blog.csdnimg.cn/blog_migrate/34bc1285f2069df4f8e0a5a81d986dac.png)
**空间局部性:**在最近的未来要用到的信息,很有可能与闲杂i正在使用的信息在存储空间上是临近的。(信息的存储一般都是顺序的)
**时间局部性:**在最近的未来要用到的信息,很可能是现在正在使用的信息。(程序中很可能存在大量的循环结构,需要重复访问)
故Cache能够工作的理论依据:从上面两个局部性可以分析到,我们可以把CPU目前访问的地址周围的部分数据放到Cache中。
(2)性能分析:
![image-20210625145403479](https://i-blog.csdnimg.cn/blog_migrate/b76ba67bfaf1517f633486303e69aee6.png)
设 **tc**为访问一次Cache所需时间,**tm**为访问一次主存所需时间。
CPU能够直接在Cache中找到所需信息,称为命中。
**命中率 H:**CPU欲访问的信息已在Cache中的比率。
**缺失率(未命中率)M:**M = 1 - H
**CPU平均访问时间 t 为:**t = H tc + ( 1-H ) ( tc+tm )
例题:
![image-20210625211029379](https://i-blog.csdnimg.cn/blog_migrate/5a2f40a013415a7d4c64f7d313109a73.png)
(3)如何界定“周围”:
![image-20210625145835025](https://i-blog.csdnimg.cn/blog_migrate/6ac32b8a15020bcb9e6294420281c4fa.png)
-
将主存的存储空间进行分块,主存与Cache之间以块为单位进行数据交换。
-
这样主存地址就可分为两部分:块号 和 块内地址。
-
在操作系统中,通常将主存中的 “一个块” 也称为 “一个页/页面/页框” 。
-
Cache中的 “块” 也称为 “行” 。
Cache和主存之间仍然存在一些问题:
- 如何区分Cache和主存之间的数据块对应关系? ——Cache和主存的映射方式
- Cache很小,主存很大。如果Cache满了怎么办? ——替换算法
- CPU修改了Cache中的数据副本,如何确保主存中数据母本的一致性? ——Cache写策略
以上问题请继续看下面内容。
总结:
3.3.2 Cache和主存的映射方式
(1)全相联映射
任何一个主存块可以放在Cache的任意位置。
给每一个Cache块增加一个标记位,记录对应的主存块号。
还需要一个有效位,有效位为1时表示标记位有效,有效位为0时表示标记位无效。
![image-20210625215055304](https://i-blog.csdnimg.cn/blog_migrate/94fd6e8e5107ea428c00592d45d4ba5b.png)
以上图为例,主存中任意一块数据都可以存放在Cache任意一块中,只要标记好和主存数据的对应就行。例如主存中第9号块数据可以存放在Cache中0号到1号任意一个位置。
优点:Cache存储空间利用充分,命中率高。
缺点:查找速度较慢。
故CPU访问主存数据的流程如下:
![image-20210625230112686](https://i-blog.csdnimg.cn/blog_migrate/fe8da86a13b5e24c31ae059eb6c875bb.png)
(2)直接映射
每个主存块只能放到特定的一个位置:Cache块号 = 主存块号 % Cache总块数。
![image-20210625215318058](https://i-blog.csdnimg.cn/blog_migrate/b17ddac84b32cc0b846a4ce197634a12.png)
以上图为例,8块为一个循环。主存中0号和8号块数据可以存放在Cache第0号块中,主存中1号和9号块数据可以存放在Cache第1号块中,以此类推。
**若Cache总块数 = 2n,则主存块号末尾 n 位直接反映它在Cache中的位置。**这是因为Cache块号 = 主存块号 % Cache总块数 = 主存块号末尾 n 位。
于是对于Cache所保存的标记号可以不用保存主存中对应的整个地址,可以只保留主存块号m前面(m-n)个二进制数。
![image-20210625230843362](https://i-blog.csdnimg.cn/blog_migrate/2a7037030ae70fbd2ff3951d9916d708.png)
故CPU访问主存数据流程如下:
![image-20210625225440110](https://i-blog.csdnimg.cn/blog_migrate/2026ea6d132e2e9865ce8fa9fccbfc6f.png)
优点:只需要对比一个标记,速度最快。
缺点:Cache存储空间不充分,命中率低。
(3)组相联映射
将Cache块分为若干组,每个主存块可放到特定分组中的任意一个位置。
每个主存块对应的组号 = 主存块号 % 分组数
![image-20210625215617471](https://i-blog.csdnimg.cn/blog_migrate/2849b9bff280f3dbb9deb9a9a493ab2a.png)
以上图为例,8块为一个循环组。0号和8号同属于第0组,0号和8号数据可以存放在第0组的任意一个位置,只要做好标记就行。
和直接映射一样,若Cache总分组数 = 2n,则主存块号末尾 n 位直接反映它在Cache中是第几组。
![image-20210625230936046](https://i-blog.csdnimg.cn/blog_migrate/06d2258caef4cc8ad325410929375692.png)
故CPU访问主存数据流程如下:
假设以下采用2路组相联映射,也就是 2块为一组,分四组。
![image-20210625231648988](https://i-blog.csdnimg.cn/blog_migrate/25195edef250498bd2bbbe52b1d40daf.png)
优点:上面两种方法的折中,综合效果较好。
总结:
3.3.3 Cache替换算法
知识总览:
![image-20210625232724991](https://i-blog.csdnimg.cn/blog_migrate/392b0b3dc0dc05a4ec785db7621b48cf.png)
直接映射方式 由于主存数据块对应的Cache块是固定的,所以没得选择,不需要使用替换算法。
而全相联映射和组相联映射方式 由于可以选择不同位置进行替换,所以需要用到替换算法进行替换。
下面例子以全相联映射方式进行举例。
1.随机算法(RAND)
-
若Cache已满,则随机选择一块替换。
举例:
图中红色表示该位置被重新替换成新的块。
图中绿色表示命中该缓存块。
![image-20210625233144880](https://i-blog.csdnimg.cn/blog_migrate/e99b8d6fa6045ecae1d372519f82277e.png)
- 随即算法实现简单,但完全没考虑局部性原理(时间局部性),命中率低,实际效果很不稳定。
2.先进先出算法(FIFO)
- 若Cache已满,则替换最先被调入Cache的块。
举例:
![image-20210625233517197](https://i-blog.csdnimg.cn/blog_migrate/750ee449469079dd24b3783960427759.png)
从上图可以看到,红色出现很多次,这表明缓存块被频繁地替换,刚被替换的块很快又被重新调入,这称为抖动现象。
- 先进先出算法实现简单,但是依然没考虑局部性原理(时间局部性),因为最先被调入Cache的块也可能是被频繁访问的。
3.近期最少使用(LRU)
- 为每一个Cache块设置一个”计数器“,用于记录每个Cache块已经多久没被访问过了。当Cache满了之后替换”计数器“最大的。
- 计数规则:
- 命中时,所命中的行的计数器清零,比其低的计时器加1,其余不变(加一没有意义)。
- 未命中且还有空闲行时,新装入的行的计数器置0,其余非空闲行全加1。
- 未命中且没有空闲行时,计数值最大的行的信息块被淘汰,新装行的块的计数器置0,其余全加1。
举例:
一开始,缓存块中并没有存储数据,计数器均为0。
![image-20210625234519059](https://i-blog.csdnimg.cn/blog_migrate/c0cecb732d8bb1972f0a8645fda9b002.png)
访问主存块1
![image-20210625234542103](https://i-blog.csdnimg.cn/blog_migrate/8998d1b93977d71e4bb009a56e478e63.png)
访问主存块2
![image-20210625234624359](https://i-blog.csdnimg.cn/blog_migrate/8bf168b0e8894253b16c9b757108a33b.png)
访问主存块3
![image-20210625234657672](https://i-blog.csdnimg.cn/blog_migrate/68fb7d86452a8f334165ff4bf419abda.png)
访问主存块4
![image-20210625234726007](https://i-blog.csdnimg.cn/blog_migrate/babde9394108b1c1002f226bcc8249c1.png)
访问主存块1,命中缓存,Cache0计数器重新清零
![image-20210625234816616](https://i-blog.csdnimg.cn/blog_migrate/0990d204ae5c21ce550d4fe3b338f35f.png)
访问主存块2,命中,Cache1计数器重新清零
![image-20210625234946039](https://i-blog.csdnimg.cn/blog_migrate/69297c6dfc7f58ab0f0892e9a9c08045.png)
访问主存块5,此时未命中,将会采取下先进先出算法,替换计数值最大的块,图中替换Cache2
![image-20210625235057355](https://i-blog.csdnimg.cn/blog_migrate/a669e65b38546cd870f36ca0b112cc7d.png)
接下来的流程和上面类似,只需要根据计数规则自行模拟即可,这里不再赘述。
- 近期最少使用算法 基于 局部性原理,近期被访问过的主存块,在接下来的时间内很可能还会被访问,因此淘汰最久没被访问过的块是合理的,该算法实际运行效果优秀,Cache命中率很高。
- 若被频繁访问的主存块的数量 > Cache行的数量,则还是有可能发生抖动。
4.最近不经常使用(LFU)
-
为每一个Cache块设置一个”计数器“,用于记录每个Cache块被访问过几次。当Cache满后替换“计数值”最小的。
-
新调入的块计数器=0,之后每被访问过一次计数器+1。
举例:
访问了主存块1号,2号,3号,4号后,Cache的状态:
![image-20210626000456276](https://i-blog.csdnimg.cn/blog_migrate/3eef2e70ae32e9df85592a418119eb22.png)
访问主存块1号和2号时均命中,Cache0和Cache1计数器加一。当访问主存块5号时,未命中,于是会替换计数值最小的Cache2(这里Cache2和Cache3均为0,会按行号递增或者FIFO策略来进行选择哪一个被替换)
![image-20210626000613697](https://i-blog.csdnimg.cn/blog_migrate/631858a77a3b4cfb100f516f6c2a27c6.png)
接下来的流程和上面类似,根据 最不经常使用算法 自行模拟即可,这里不再赘述。
- 评价:曾经被经常访问的内存块在未来并不一定仍然被访问,并没有很好地遵循局部性原理(时间局部性原理),因此实际效果并不如 近期最少使用算法 LRU。
总结:
3.3.4 Cache写策略
知识总览:
![image-20210626001754786](https://i-blog.csdnimg.cn/blog_migrate/96836f0e351308eb9e66b9c1d992e544.png)
为何不讨论读命中,读不命中的情况?
因为读不会导致主存和Cache的数据不一致。
1.写命中
(1)写回法:
-
当CPU对Cache写命中时,只修改Cache的内容,而不立即写入主存,只有当此Cache块被替换时才写回主存。
-
需要增加一位脏位,用于标记该Cache块是否被修改了。
-
减少了访存的次数,但存在数据不一致的隐患。
(2)全写法:
- 当CPU对Cache块写命中时,必须把数据同时写入Cache和主存中,一般使用写缓冲(write buffer)。
- 访存次数增加,速度变慢,但能保证数据的一致性。
- 使用写缓冲,CPU写的速度很快,若写操作不频繁,则效果很好,若写操作很频繁,可能会因为写缓冲饱和而发生阻塞。
2.写不命中
(1)写分配法:
- 当CPU对Cache写不命中时,把主存中的块调入Cache中,在Cache中修改,通常搭配写回法使用。也就是发生替换时才写回主存。
(2)非写分配法:
- 当CPU对Cache写不命中时,只写入主存,不调入Cache中。搭配全写法使用。
3.多级Cache
![image-20210626120804700](https://i-blog.csdnimg.cn/blog_migrate/5439ec8a674460cd04768529406207a7.png)
现代计算机常采用多级Cache:
-
离CPU越近的速度越快,容量越小
-
离CPU越远的速度越慢,容量越大。
各级Cache之间常采用 全写法 + 非写分配法。
Cache 和 主存 之间常采用 写回法 + 写分配法。
总结:
3.4 虚拟存储系统
3.4.1 页式存储
有时候一个程序比较大,无法将它顺序地存放在主存中的各个块中,因此操作系统会将它分成若干个页面,页面的大小和块的大小相同,每个页面可以离散地放入不同的主存块中。
逻辑地址(虚地址):程序员看到的地址。
物理地址(实地址):实际在主存中的地址。
对于一条机器指令:000001 001000000011(操作码+地址码),其地址码所使用的就是 逻辑地址。
页表:记录了每个逻辑页面存放在哪个主存块中,页表的数据放在主存中。
![image-20210626152212018](https://i-blog.csdnimg.cn/blog_migrate/060a14481eeb8961ba9454964ecc3f8e.png)
地址变换过程:举例
假设此时执行一条取指令操作,该指令为 000001 001000000011,所以要取的数据的逻辑地址为 001000000011
- 首先将逻辑地址拆分成 逻辑页号 和 页内地址。
- 在主存中找到 页表,然后通过 逻辑页号 进行查表,查出对应的 主存块号。
- 将 主存块号 拼接 页内地址 得到最终的 物理地址。
- 到Cache中查找该物理地址,找不到的话再到主存找。
但是由于页表是存放在主存中的,而根据时间局部性原理,刚使用的数据很可能在接下来还会使用,这样在下一次使用该数据时又得访问一次主存进行查表,为了更快地查表,会将近期访问的页表项放入更高速的存储器中,称为 快表。
**快表:**快表是一种相联存储器,可以按照内容进行寻访,并且其采用的是SRAM,访问速度更快。
快表 和 Cache 的区别:
- 快表 存储的是 页表项的副本
- cache 存储的是 主存块的副本
总结:
![image-20210626154413090](https://i-blog.csdnimg.cn/blog_migrate/8f7f74cb94eb824f6f3528fb08bd075a.png)
3.4.2 虚拟存储器
**虚拟存储系统:**辅存中的数据并不是一次性全部加载到主存中的,而是和 Cache——主存 类似,根据局部性原理加载一部分数据到主存中。
举例:打游戏时的“Loading”界面背后可能就是在 将游戏地图相关数据调入内存中。
1.页式虚拟存储器
和Cache、主存类似,辅存中数据也被分为一个一个的块。
![image-20210626163252564](https://i-blog.csdnimg.cn/blog_migrate/3c2621a3dce6816fcbe62813612ab58b.png)
为了实现只加载一部分数据到主存中,需要对页表补充一些信息。
![image-20210626163036547](https://i-blog.csdnimg.cn/blog_migrate/89eb1786e9adcea6cf91624c85d370d1.png)
-
逻辑页号:逻辑地址中的页号
-
主存块号:物理地址中的主存块号
-
外存块号:辅存中对应的块号
-
有效位:这个页面是否被调入主存中
-
访问位:用于页面替换算法,主存也有用完的时候,需要进行替换,例如可以使用最不经常使用算法,统计访问次数。
-
脏位:这个页面是否被修改过,修改主存后会导致主存和辅存之间数据不一致。
由于主存和辅存之间的数据调入是由操作系统来调控的,因此具体细节请看操作系统相关内容,以上仅做粗略介绍。
![image-20210626163933234](https://i-blog.csdnimg.cn/blog_migrate/28bebb25e2a4f6c38fea4bf078e47f60.png)
- **主存——辅存:**实现虚拟存储系统,解决了主存容量不足的问题。
- **Cache——主存:**解决了主存和CPU之间速度不匹配的问题。
2.段式虚拟存储器
按照功能模块进行拆分。
例如:#0段是自己的代码,#1段是库函数的代码,#2段是变量。
![image-20210626164416891](https://i-blog.csdnimg.cn/blog_migrate/9a60a12d6534b5787448dfbf4af6bdc7.png)
和页式存储类似,操作系统以段为单位来决定哪一些段应该被调入内存中。
![image-20210626164555468](https://i-blog.csdnimg.cn/blog_migrate/6fda60af7cce5b6fd2621560fade30eb.png)
3.段页式虚拟存储器
把程序先按功能模块分段,每段再划分为固定大小的页,主存空间也划分为大小相等的页。
程序对主存的调入,调出仍然以页为基本传送单位,每个程序对应一个段表,每段对应一个页表。
虚拟地址:段号 + 段内页号 + 页内地址。
具体详情请看操作系统内容。