3.1 存储系统的基本概念
存储器的层次结构
- 存储器的层次结构如下图:
越靠近上层的速度越快、容量越小、价格越高。 - 存储器有Cache-主存层和主存-辅存层。辅存中的数据要调入主存后才能被CPU访问。存储器和CPU之间的调用关系如图所示:
添加Cache层是为了缓解CPU速度和主存读写速度之间的矛盾。
最接近CPU的是寄存器,寄存器比Cache速度更快,寄存器在CPU内部,个数很有限。 - 主存和辅存之间的数据交换是靠硬件和OS实现的。OS需要实现页面置换算法。
- 主存-辅存:实现了虚拟存储系统,解决了主存容量不够的问题。实现了虚拟系统之后,应用程序员看到的主存容量可以比实际容量大很多。
Cache-主存:解决了主存与CPU速度不匹配的问题。
存储器的分类
按存储介质分类
- 半导体存储器(以半导体器件存储信息):主存、Cache
- 磁表面存储器(以磁性材料存储信息):磁盘、磁带
- 光存储器(以光介质存储信息):光盘
按存取方式分类
其中第2和第3类可以归为串行访问的存储器,即读写某个存储单元所需时间与存储单元的物理位置有关。
- 随机存取存储器(Random Access Memory,RAM):读写任何一个存储单元所需要时间都相同,与存储单元所在物理位置无关,如内存条。
- 顺序存取存储器(Sequential Access Memory, SAM):读写一个存储单元所需时间取决于这个存储单元所在物理位置。如磁带
- 直接存取存储器(Direct Access Memory, DAM):既有随机存取特性,也有顺序存取特性。先直接选取信息所在区域,然后按顺序方式存取。
- 相联存储器(Associative Memory):即可以按内容访问的存储器(Content Addressed Memory)。可以按照内容检索到存储位置进行读写,“快表”就是一种相联存储器。这种和前三种的区别是前三种按地址访问,第四个按内容访问。
按信息的可更改性分类
- 读写存储器(Read/Write Memory):可读写,如磁盘、内存、Cache。
- 只读存储器(Read only Memory):只能读,不能写。如实体音乐专辑通常采用CD_ROM, 实体电影采用蓝光光碟,BIOS系统通常写在ROM中。但其实现在的ROM也可以多次写,但是会比较麻烦。
按信息的可保存性分类
- 断电后,存储信息消失的存储器:易失性存储器(主存、Cache)
- 断电后,存储信息依然保持的存储器:非易失性存储器(磁盘、光盘)
- 信息读出后,原存储信息被破坏:破坏性读出(如DRAM芯片、读出数据后要进行重写)
- 读出信息后,原存储信息不被破坏:非破坏性读出(如SRAM芯片、磁盘、光盘)
存储器的性能指标
- 存储容量:\(存储字数 \times 字长\),如\(1M \times 8位\)
- 单位成本:每位价格 = 总成本/总容量
- 存储速度:数据传输率 = 数据的宽度/存储周期。
数据的宽度就是存储字长
存储周期 = 存取时间 + 恢复时间- 存取时间\(T_a\): 从启动一次存储器操作到完成该操作所经历的时间,分为读出时间和写入时间。
- 存取周期\(T_m\): 存取周期又称为读写周期或访问周期。指存储器进行一次完整的读写操作所需的全部时间,即连续两次独立的访问存储器操作之间所需的最小时间间隔。
- 主存带宽(\(B_m\)):又称数据传输率,表示每秒从主存进出信息的最大数量,单位为字/秒、字节/秒或位/秒。
3.2.1 主存储器的基本组成
半导体元件的原理
- 存储器结构如下图所示,存储器、地址寄存器和数据寄存器之间会在时序电路的控制下相互配合。
其中存储体是由存储单元构成的。每个存储单元是由存储元(MOS管+电容)构成。如果各个存储元可以科学有序的排列,就可以一次读写多位。存储单元由一排存储元构成,存储体由存储单元构成,也成为存储矩阵。 - 如何根据地址决定读/写哪个存储字呢?
- 这里用到了译码器,给译码器输入n位地址,对应\(2^n\)个存储单元。译码器会根据输入地址,将某位字选线输出信号置为高电平。每一个地址都会对应一条字选线的1.
- 除此之外译码器前面还要加一个控制电路,作用是保证MAR信号稳定时才能输入到译码器中。也保证译码器输出信号稳定之后才会传给MDR。
- 另外,存储器中还有片选线,用\(\overline {CS}\)(chip select)或\(\overline {CE}\)(chip enable)表示,上面加横线的表示方式意为低电平有效。
- 存储器还需对外提供两个读/写控制线。\(\overline {WE}\)(允许写)、\(\overline {OE}\)(允许读)。还可以把这两个信号合二为一,低电平写、高电平读。这样存储器芯片对外暴露的引脚数目是不一样的。
存储芯片的基本原理
片选线的作用是选择具体芯片。
- 会有一种题目问一个芯片最少有多少引脚。芯片的引脚包括地址线、数据线、一位片选线、读写控制线。另外根据题目的信息,也许还有供电引脚、接地引脚。
如何实现不同的寻址方式
以上图为例,一个小方格8位,机器字长32位。现代计算机通常采用字节编址,有1KB的容量就有1K个地址,每个地址对应1B的容量。现代计算机还支持其他的寻址方式,如下表所示:
寻址方式 | 地址单元数量 | 每个地址数据容量 | 地址线数量 |
---|---|---|---|
按字节寻址 | 1K | 1B | 10 |
按字寻址 | 256 | 4B | 8 |
按半字寻址 | 512 | 2B | 9 |
按双字寻址 | 128 | 8B | 7 |
3.2.2 SRAM和DRAM
DRAM(Dynamic Random Access Memory), 动态RAM
SRAM(Static Random Access Memory),静态RAM
DRAM用于主存,SRAM用于Cache。
高频考点:DRAM和SRAM的对比
DRAM芯片
- 使用栅极电容存储信息(一根数据线读0/1)
- 破坏性读出:读信息是1的时候MOS管接通,电容放电,数据线上产生电流。读信息是0的时候,数据线上无点流。读出后应有重写操作,也称“再生”。
- 读写速度更慢。
- 制造成本更低
- 集成度更高
- 功耗低
- 容量大
- 现在的计算机一般不用DRAM了,用SDRAM芯片
SRAM芯片
- 使用双稳态触发器存储信息(两根数据线读0/1)
- 非破坏性读出,不需要重写。
- 读写速度更快。
- 制造成本更高
- 集成度更低
- 功耗高
- 容量小
DRAM和SRAM的对比
- 电容里面存储的电荷容易消失,所以DRAM需要“刷新”来更新数据。
- 送行列地址SRAM是分同时送,DRAM是分两次送。分两次送的作用是可以用同一批地址线传输行和列地址,这样地址线变成原来的一半。
DRAM的刷新
- 多久刷新一次?
一般电容里的电荷能坚持2ms,所以刷新周期是2ms - 每次刷新多少存储单元?
以行为单位,每次刷新一行。
对于有n位MRA的译码器,一共有\(2^n\)跟字选线。如果所有存储单元都一维排列的话,译码器集成\(2^n\)根线是较为困难的。所以把字选线分成行字选线和列字选线,译码器分为行译码器和列译码器,每个处理\(2^{n/2}\)的字选线,把存储单元按矩阵形式排列。 - 如何刷新?
有硬件支持,读出一行的信息后重新写入,占用1个读写周期。 - 何时刷新?
- 分散刷新:每次读写完都刷新一行,系统的存取周期翻倍,前一个存取周期正常读写,后一个存取周期用来刷新某行。
- 集中刷新:2ms内集中安排时间全部刷新,系统的存取周期不变,但有一段专门的时间用于刷新,无法访问存储器,称为访存“死区”。
- 异步刷新:2ms内,每行刷新1次即可,每隔2ms/n(行)刷新一次,每2ms/n(行)时间内有一个存取周期的“死时间”。可以在不需要存取(译码)的时间进行刷新。
- 刷新操作由存储器独立完成,不需要CPU控制。
3.2.3 只读存储器ROM
ROM芯片是非易失性的。
很多ROM芯片也有随机存取的特性
MROM
- MROM(Mask Read-Only Memory): 掩模式只读存储器
- 厂家按照客户需求,在芯片生产过程中直接写入信息,之后任何人不可重复写(只能读出)
- 可靠性高、灵活性差、生产周期长,只适合批量定制。
PROM
- PROM(Programmable Read-Only Memory): 可编程只读存储器
- 用户可用专门的PROM写入器写入信息,写一次之后不可更改。
- 比MROM灵活性高。
EPROM
- EPROM(Erasable Programmable Read-Only Memory): 可擦除可编程只读存储器
- 允许用户写入信息,之后用某种方式擦除数据,可进行多次重写
- UVEPROM(ultraviolet rays)——用紫外线照射8~20分组,擦除所有信息。
- EEPROM(electrically)——可用“电擦除”方式,擦除特定的字。
Flash Memory
- 闪速存储器(U盘、SD卡)
- 在EEPROM基础上发展而来,断电后也能保存信息,且可进行多次快速擦除重写
- 注:由于闪存需要先擦除再写入,因此闪存的“写”速度要比“读”速度更慢。
- 每个存储元只需要单个MOS管,位密度比RAM高
- 手机辅存也用的是Flash芯片,但比SSD使用的Flash芯片集成度高、功耗低、价格更高
SSD
- SSD(Solid State Drives): 固态硬盘
- 由控制单元+存储单元(Flash芯片)构成。与闪存的核心区别是控制单元不一样,但存储介质都类似,可进行多次快速擦除重写。
- SSD速度快、功耗低、价格高。目前个人PC上常用SSD取代传统机械硬盘。
计算机内的重要ROM
- 主板上的BIOS芯片:
BIOS存有自举装入程序,是电脑开机时CPU首先执行的程序,主要负责将辅存中的OS调入主存。这段程序是用来引导开机的。 - 虽然这个芯片被放在主板上,但是在计组课程中默认它是主存的一部分,BIOS和RAM结合才是完整的主存。BIOS会和RAM统一编址。BIOS的地址紧跟着是RAM的地址。
3.2.4 双端口RAM和多模块存储器
- 存取周期:可以连续读写的最短时间间隔。
注:DRAM芯片的恢复时间比较长,可能是存取时间的几倍,SRAM的恢复时间较短。
双端口RAM
- 作用:优化多核CPU访问一根内存条的速度。
两个端口对同一主存操作有一下4种情况:
- 两个端口同时对不同地址单元存取数据。
这种操作可以支持。 - 两个端口同时对同一地址单元读出数据。
读操作不改变存储单元的数据,这个操作也支持。 - 两个端口同时对同一地址单元写入数据。
会出现写入错误,可能出现数据的相互覆盖。 - 两个端口同时对同一地址单元一个写入、另一个读出数据。
不支持,可能出现读出错误。
出现3和4的情况,RAM会给CPU一个忙信号,然后按照一定规则关闭某个端口。
多体并行存储器
- 多体并行存储器可以理解为有4根内存条
- 有两种编址方式:
每个地址包括体号和体内地址两部分,体号用来区分数据存在哪个内存条上,体内地址用来指明数据存在这个内存条的什么位置。- 高位交叉编址:地址的高位表示内存条选择信号
- 低位交叉编址:地址的低位表示内存条选择信号
- 加数每个存储体的存取周期为T,存取时间为r,假设T = 4r,那么CPU对存储体的访问过程可以由如下的甘特图所示:
- 高位交叉编址:
说明:存储体结构如上面的示意图,地址的前两位是存储体地址,后3位是体内地址。连续访问的地址都在\(M_0\)上。 - 低位交叉编址:
总耗时T + 4r = 2T
连续存取n个存储字的总耗时为T + (n - 1)r
宏观上读写一个字的时间接近r。
- 高位交叉编址:
- 为什么要探讨“连续访问”的情况?
因为指令和数据很多时候都是在内存中连续存储的。 - 为了使存取效率更高,应该取几个体?
采用流水线的方式并行存取(宏观上并行,微观上串行)
宏观上,一个存储周期内,m体交叉存储器可以提供的数据量为单个模块的m倍。
存储周期为T,存取时间为r,为人使流水线不间断,应保证模块数\(m \geq T/r\)。由于存储体增加成本会增加,所以当m = T/r时,效率最高。 - 每个模块都有相同的容量和存取速度。
- 各模块都有独立的读写控制电路、地址寄存器和数据寄存器。它们既能并行工作,又能交叉工作。
单体多字存储器
- 每个存储单元存储m个字
- 总线宽度也为m个字
- 一次并行读出m个字
- 不能单独选择读取其中的某个字,指令和数据在主存内必须是连续存放的。但是读数据的时候可能会读出一些冗余信息。但是对于读取速度的提升来说,多体和单体多字对时间的节约都差不多
3.3.1 主存与CPU的连接
单块存储芯片与CPU的连接
上图只使用了但芯片,只可以存储8B信息,想要扩展主存字数怎么办?
- 当数据总线宽度 > 存储芯片字长时采用位扩展。
- 注:现代计算机的MAR和MDR通常集成在CPU中。MAR里的地址数据是通过地址总线传给主存,MDR是通过数据总线根主存交换数据。现在的主存中一般有很多芯片。
- 存储器芯片的输入输出信号:
- 地址线:\((A_7...A_0)\)
- 数据线:\((D_7...D_0)\)
- 片选信号:\(\overline {CS} 或 \overline {CE}\),低电平有效;
CS 或 CE,高电平有效。 - 读写控制线:\(\overline {WE} 或 \overline {WR}\),低电平表示写,高电平表示读。
也可能分开为\(\overline {WE} 和 \overline {OE}\)两个读写线。
位扩展
现在有一块\(8K \times 1位\)的芯片如何与CPU连接?
CPU和芯片的图示如下:
8k -> 地址线有13根,所以存储芯片的\(A_{12}\) ~ \(A_0\)对应连接到CPU的\(A_{12}\) ~ \(A_0\)上。芯片上的WE连接在CPU的WE上,由于只有1位,所以芯片上的\(D_0\)连接在CPU的\(D_0\)上。由于目前只有一块芯片,所以最上面的片选信号可以直接接1.
由于数据线使用不充分,可以对存储字长进行位扩展,再加7个\(8K \times 1\)位的芯片,数据线分别连接在CPU的剩余各数据线上,其余线连接和第一块芯片相同。
字扩展
译码器片选法:
上例的芯片变成\(8k \times 8\)位数据线占满CPU的数据线,地址线占用了0~12位,还有13、14、15的地址线空闲,可就可以进行位扩展,再拿7个\(8k \times 8\)位的芯片,将CPU的\(A_{13}到A_{15}\)连接一个译码器,译码器共输出8根线,将这八根线对应连接到这8个芯片的片选信号上,即可实现字扩展。
线选法:
就是CPU有n条多余的地址线,就把这些地址线对应连接到芯片的片选信号是上,这样只能多扩展n个芯片。
总结:
字扩展的两种方式:
线选法 | 译码片选法 |
---|---|
n条线 -> n个选片信号 | n条线 -> \(2^n\)个选片信号 |
电路简单 | 电路复杂 |
地址空间不连续 | 地址空间可连续 |
字位同时扩展
补充译码器知识
- 注意高电平有效还是低电平有效:
- 译码器还有一个或多个使能端en, 作用是使译码器可以工作,当使能信号有效时,译码器正常输出。当使能信号无效时,输出全为0.
3.4.1 外存
计算机的外存储器又称为辅助存储器,目前主要使用磁表面存储器。
磁表面存储器的原理图如下:
磁表面存储器每次读写都是1 bit,并且读写不能同时进行。
- 磁表面存储器优点:
- 存储容量大,位价格低;
- 记录介质可以重复使用
- 记录信息可以长时间保存而不丢失,甚至可以脱机存档
- 非破坏性读出,读出不需要再生
- 磁表面存储器缺点:
- 存取速度慢
- 机械结构复杂
- 对工作环境要求较高
外存储器既可以作为输入设备,也可以作为输出设备。
磁盘存储器
- 磁盘设备的组成:
- 存储区域:一块硬盘含有若干个记录面,每个记录面划分为若干条磁道,每条磁道又划分为若干个扇区,扇区也成为块,是磁盘读写的最小单位,也就是说磁盘按块存取。
我们说柱面号就是在指明信息在具体那一条磁道上。- 硬盘存储器:硬盘存储器由磁盘驱动器、磁盘控制器和盘片组成。
- 磁盘驱动器:核心部件是磁头组件和盘片组件,温彻斯特盘是一种可移动固定盘片的硬盘存储器。
- 磁盘控制器:是一种存储器和主机的接口,主流的标准有IDE、SCSI、SATA等。
- 在磁盘的盘片上,正反两面都可以涂上磁性材质。因此,常见的磁盘结构如下:
- 磁盘性能指标:
- 磁盘容量:一个磁盘所能存储的字节总字数。磁盘容量有格式化容量和非格式化容量之分。
非格式化容量指磁记录表面可以利用磁化单元总数。
格式化容量指按照某种特定的记录格式所能存储信息的总量(留下某些备用扇区,便于将来某些扇区损坏了还可以备用)
格式化容量小于非格式化容量。 - 记录密度:记录密度指盘片单位面积上记录的二进制信息量,通常以道密度(60道/cm)、位密度(600bit/cm)和面密度(位密度和道密度的乘积)表示
注:磁盘所有磁道记录的信息量一定是相等的,并不是圆越大信息越多,故每个磁道的位密度不同。越小的磁道位密度越大。所以磁盘整体容量很多时候受最内侧磁道的影响。 - 平均存取时间(常考):
平均存取时间 = 寻道时间(磁头移动到目的磁道) + 旋转延迟时间(磁头定位到所在扇区) + 传输时间(传输数据所花时间)
旋转延迟时间题目如果没给,就按照磁盘转半圈来计算。
有的题目还要加上磁盘控制器的延迟(就是读写控制命令的延迟) - 数据传输率:磁盘存储器在单位时间内向主机传送的字节数。
假设磁盘转数为r(转/秒),每条磁道容量为N字节,则数据传输率为rN。
- 磁盘容量:一个磁盘所能存储的字节总字数。磁盘容量有格式化容量和非格式化容量之分。
- 磁盘地址:
磁盘地址结构如下:
考查方式:若系统中有4个驱动器,每个驱动器带一个磁盘,每个磁盘256个磁道、16个盘面,每个盘面16个扇区,则每个扇区地址要2驱动器号 + 8柱面号 + 4盘面号 + 4扇区号 = 18位二进制代码。 - 硬盘工作过程
硬盘的主要操作是寻址、读盘、写盘。每个操作对应一个控制字,硬盘工作时,第一步是取控制字,第二部是执行控制字。
硬盘属于机械式部件,其读写操作是串行的,需要添加一个并-串行变换电路。这个电路的负责将并行的信号转为串行的再交给硬盘。如果有信号需要并行的交给主机,那就再利用串-并行转换电路将串行信号转换为并行信号。不可能在同时时刻既读又写,也不可能在同一时刻读两组数据或写两组数据。
磁盘阵列
RAID(Redundant Array of Inexpensive Disks, 廉价冗余磁盘阵列):是将多个独立的物理磁盘组成一个独立的逻辑盘,数据在多个物理盘上分割交叉存储、变形访问,具有更好的存储性能、可靠性和安全性。
RAID的分级如下所示。在RAID1~RAID5的几种方案中,无论何时有磁盘损坏,都可以随时拔出受损的磁盘再插入好的磁盘,而数据不会损坏。
RAID0: 逻辑上相邻的两个扇区在物理上存到两个磁盘,类似低位交叉编址多体存储器。
RAID0没有容错能力,RAID1容量减少一半。
从上至下的可靠性越来越高
3.4.2 固态硬盘SSD
思维导图:
固态硬盘的结构
固态硬盘的结构如下图所示:
- 每个块可以拆解为很多页,每个页大小大概为512B~4KB.系统对固态硬盘的读写以页为单位。
- I/O总线给闪存翻译层系统要读写的逻辑块号,这里的逻辑块号是指闪存芯片组的页号。
- 闪存翻译层负责翻译逻辑块号,找到对应页
- 固态硬盘的存储介质由多个闪存芯片组成。
- 数据以页为单位进行读写,以块为单位进行擦除。一个页如果有数据了,想要再往这个页中写数据需要把这个页所在块都擦除,之后再写。
- 固态硬盘的逻辑地址对应的物理地址可能会改变,到那时闪存翻译层会把这个对应关系管理好。
- 磨损均衡技术:把“擦除”平均分布在各个块上,以提升使用寿命。
3.5.1 Cache的基本概念和原理(重中之重)
Cache的工作原理
- 计算机启动时,会把辅存的一部分CPU要执行的代码内容复制到主存中,但是主存和CPU之间的速度差异很大,为了适应CPU的速度,可以把近期频繁使用的一部分代码复制到cache中,CPU直接访问Cache。Cache的速度比内存快很多,速度的矛盾被缓和。
- Cache现在已经被集成到CPU内部,用SRAM实现,速度快,成本高。
程序的局部性原理
- 空间局部性:在最近的未来要用到的信息(指令和数据),很可能与现在正在使用的信息在存储空间上时邻近的。
e.g. 数组元素、顺序执行的指令代码 - 时间局部性:在最近的未来要使用的信息,很可能是现在正在使用的信息。
e.g. 循环结构的指令代码 - 基于局部性原理,不难想到,可以把CPU目前访问的地址“周围”的部分数据放到Cache中。
性能分析
设\(t_c\)为访问一次Cache所需时间,\(t_m\)为访问一次主存所需时间。
- 如果CPU想要的数据能在Cache中找到,就成为Cache命中。
- 命中率H:CPU欲访问的信息已在Cache中的比率。
- 缺失(未命中)率:M = 1 - H
- Cache-主存系统的平均访问时间t为:
当CPU先去Cache中找,如果找不到再去内存里找:
CPU还可以同时去Cache和内存里找,如果在Cache里找到,立刻停止对内存的查找,如果\(t_c\)时间内在Cache里没找到,那就需要\(t_m\)的时间在内存里找到。这种情况的平均访问时间为:
\[t = Ht_c + (1 - H)t_m \]例:假设Cache的速度是主存的5倍,且Cache的命中率是95%,则采用Cache后,存储器的性能提升多少?(设Cache和主存同时被访问,若Cache命中则中断访问主存)
解:设Cache的存取周期为t,则主存的存取周期为5t。
使用Cache的平均访问时间为:
T = 0.95 * t + 0.05 * 5t = 1.2t
性能变成原来的:5t/1.2t = 4.17倍
待解决的问题
- 基于局部性原理,可以把CPU目前访问的地址“周围”的部分数据放到Cache中,如何界定“周围”?
- 可以将主存的存储空间“分块”,如每1KB为1块,主存与Cache之间以“块为单位进行数据交换”
- 例如一个4MB的主存,分为1KB的块,按字节编址。
4M = \(2^{22}\), 1K = \(2^{10}\)整个主存被分为4096块。主存的地址共22位,其中块号12位,块内地址10位。
在OS中,通常将主存中的一个块也成为一个页、一个页面、一个页框。
Cache中的块也称为行。
每次被访问的主存块,一定会被立即调入Cache中。(复制到Cache中)
3.5.2 Cache和主存的映射方法
- 如何区分Cache中存放的是哪个主存块?
给每个块增加一个标记,记录对应的主存块号。 - 另外,Cache初始状态下所有位都是0,标记为0并不能说明此时Cache中存放的是主存0号位置的信息。所以还需要添加有效位,有效位为1时表示此时Cache中有主存信息,有效位为0时表示此时Cache中没有存放主存信息。
全相联映射
全相联映射就是主存的信息可以存放在Cache中的任何位置。
- 假设某个计算机的主存地址空间大小为256MB,按字节编址,其数据Cache有8个Cache行,行长为64B.
Cache块和主存块的大小相等。
Cache有8 * 64B = 512B
主存256MB,可以被划分为22位主存块号和6位块内地址。 - 在把主存块放到Cache中之前,Cache的有效位和标记位都是0,当某个主存块需要放进Cache的某块中,给这个Cache块有效位置一,标记位(22位)存放主存块的块号,然后把主存块的内容存到这个Cache块中。
- CPU访问主存地址时:
- 主存地址的前22位对比Cache中的所有块的标记
- 如果标记匹配且有效位=1,则Cache命中,访问块内地址然后再访问块内地址为后六位地址的单元。
- 若未命中或有效位为0,则正常访问主存。
- 优点:空间利用充分,命中率高
- 缺点:查找标记最慢,有可能要对比所有行的标记
直接映射
每个主存块只能放在特定位置。
主存块在Cache中的位置 = 主存块号 % Cache总数
- 优点:对于任意一个地址,只需对比一个标记,速度最快。
- 缺点:取余结果相同的两个块不能同时存到Cache中,第二个要存进去必须把第一个擦掉。灵活性差一些,空间利用率不充分。
- 同样的例子,(主存22为主存块号、6位块内地址),但是由于Cache映射方式是“主存块号 % Cache总数”,相当于Cache块号体现了主存块号的后3位,也就是说标志位可以简化到19位,就足以表示主存块号。
- 采用直接映射的方式主存地址结构可以表示为19位标记位,3位Cache行号,6位块内地址。
- CPU访问主存地址:
- 根据主存块号的后3位确定Cache行
- 若主存块号的前19位与Cache标记匹配且有效位为1,则Cache命中,根据块内地址访问块中的单元。
- 若未命中或有效位为0,则正常访问主存。
组相联映射
将Cache块分组,每个主存块可以放到特定的分组中的任意部分。
n路组相联含义为n个Cache块为1组,主存块所属分组 = 主存块号 % 分组数。
- 上面的例子采用二路组相联,Cache块分为4组。相当于主存块的后两位表示的是分组号,所以Cache的标记位需要22-2=20位即可。
- 采用组相联映射,主存块的地址结构为:20位标记位、2位组好位、6位块内地址。
- CPU访问主存地址过程:
- 根据主存块号的后2位确定所属分组号
- 比对该分组内所有块,若主存块号的前20位与标记匹配且有效位为1,则Cache命中,访问Cache内的特定地址单元。
- 若未命中或有效位为0,则正常访问主存。
- 优点:另外两种方式的折中,综合效果较好
3.5.3 Cache替换算法
解决Cache装满了之后该怎么办的问题。
- 对于全相联映射,Cache完全满了才需要在全局中选择替换某一块
- 直接映射如果对应位置非空,则需要毫无选择的之间替换
- 组相联映射等分组满了之后需要在分组内选择替换哪一块。
随机算法RAND
- 随机算法(Random)——若Cache已满,则随机选择一块替换。
设总共有4个主存块,初始整个Cache为空,采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}
则随机算法的一种访问情况如下表所示:
访问主存块 | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Cache #0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 4 | 4 |
Cache #1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | |
Cache #2 | 3 | 3 | 3 | 3 | 5 | 5 | 5 | 5 | 5 | 5 | ||
Cache #3 | 4 | 4 | 4 | 4 | 4 | 4 | 3 | 3 | 3 | |||
Cache命中? | 否 | 否 | 否 | 否 | 是 | 是 | 否 | 是 | 是 | 否 | 否 | 是 |
Cache替换? | 否 | 否 | 否 | 否 | 否 | 否 | 是 | 否 | 否 | 是 | 是 | 否 |
- 优点:实现简单
- 缺点:但完全没考虑局部性原理,命中率低,实际效果很不稳定。
先进先出算法FIFO
- 先进先出算法(First in First out)——若Cache已满,则替换最先被调入Cache的块
- 设总共有4个主存块,初始整个Cache为空,采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}
则先进先出算法的一种访问情况如下表所示:
- 优点:实现简单,最开始按#0#1#2#3放入Cache,之后轮流替换#0#1#2#3。
- FIFO依然没有考虑局部性原理,最先被调入的Cache的块也可能被频繁访问。可能出现抖动现象:频繁的换入换出
近期最少使用LRU
- 近期最少使用算法(Least Recently Used)——为每个Cache设置一个计数器,用于记录每个Cache块已经有多久没被访问了。当Cache满后替换计数器最大的。
- 设总共有4个主存块,初始整个Cache为空,采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}
替换的简便方法是,当需要替换时,从这一位往前看,最近没有被访问到的替换掉,例如当访问到5时Cache已满,此时往前看依次访问了2、1、4,所以3最近没有访问到,替换3.之后访问3的时候又需要替换,往前看分别访问了2、1、5,所以替换4,后面访问4,往前看是3、2、1,替换5,最后访问5,前面是4、3、2,替换1.
计数器的计数方式:- 命中时,所命中的行的计数器清零,比其低的计数器加1,其余不变。
- 未命中且还有空闲行时,新装入的行的计数器置0,其余非空闲行全加1.
- 未命中且无空闲行时,计数值最大的行的信息块被淘汰,新装行的块的计数器置0,其余全加1.
- 这样的规则保证了计数器最大值 = Cache块总数- 1,如果有\(2^n\)的Cache块,那计数器有n位即可。
- 基于局部性原理,近期被访问的主存块,在不久的将来也很有可能被再次访问,因此淘汰最久没有被访问过的块是合理的。LRU算法的实际运行效果优秀,Cache命中率很高。
- 但如果被频繁访问的主存块的数量 > Cache行的数量,可有可能发生抖动。
最近不经常使用FRU
- 最近不经常使用算法(Least Frequently Used)——为每个Cache块设置一个计数器,用于记录每个Cache块被访问过几次。当Cache满后替换计数器最小的
- 计数器的记录规则:
- 新调入的块计数器 = 0,之后每被访问一次计数器+1,需要替换时,选择计数器最小的一行,若有多个计数器最小行,可按照行号递增或FIFO策略进行选择。
- 同样的例子替换表格如下:
- LFU算法:曾经经常被访问的主存块在未来不一定会用到,并没有很好的遵循局部性原理,实际运行效果不如LRU
3.5.4 Cache写策略
为了保证Cache和主存内容的一致性。
写命中
全写法
- 全写法(写直通法,wirte-through)——当CPU对Cache写命中时,必须把数据同时写入Cache和主存,一般使用写缓冲(write buffer)。
- Cache块被替换时无需写回。
- 访存次数增加,速度变慢,但能保证数据的一致性
- 写缓冲:用SRAM实现的FIFO队列:
CPU在对Cache写数据的时候也要把数据写到写缓冲里,在专门的控制电路控制下逐一谢辉主存。 - 增加了写缓冲之后,CPU写的速度很快,若写操作不频繁,则效果更好,若写操作很频繁,可能会因为写缓冲饱和而发生阻塞。
写回法
- 写回法(Write-back)——当CPU对Cache写命中时,只修改Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存。
- Cache行要添加一个脏位信息,用来标记Cache行是否被写了数据。脏位为1表示被修改过,脏位为0表示没有被修改过。
- 写回法减少了访存次数,但存在数据不一致的隐患。
写不命中
- 写分配法(write-allocated)——当CPU对Cache写不命中时,把主存的块调入Cache,在Cache中修改。通常搭配写回法使用。
- 非写分配法(not-write-allocated)——当CPU对Cache写不命中时,只写入主存,不调入Cache,搭配全写法使用。
这种方法下只有CPU读未命中时才把未命中的内容调入Cache
多级Cache
- 现代计算机常采用多级Cache
- 离CPU越近速度越快,容量越小。
- 离CPU越远速度越慢,容量越大。
- 各级Cache之间常采用“全写法+非写分配法”;
Cache-主存之间常采用“写回法+写分配法。”
3.6.1 页式存储器
页式存储
- 分页:
分页是对于程序而言,一个较大的程序如果直接存放到主存中,那可能需要很大的一块地址空间。所以采用分页的方式把一个程序分割开。
例如:一个4KB的程序被分为4个页,每个页面的大小和物理块的大小相同。这四个页面可以离散的放到主存中。 - 页式存储系统:一个程序(进程)在逻辑上被分为若干个大小相等的“页面”,“页面”大小与“块”大小相同。每个页面可以离散的放入不同的主存块中。
- 把程序(进程)分页是一个逻辑上的划分,把一个主存和Cache分块是物理上的划分。
虚地址和实地址
- 逻辑地址(虚地址):程序员视角看到的地址
- 物理地址(实地址):实际在主存中的地址
地址变换过程
- 例如某程序4KB,程序员视角\(4KB = 2^{12}B\), 地址范围0000 0000 0000~1111 1111 1111 1111.
- 假设某变量x的逻辑地址:0010 0000 0011
- 变量y的逻辑地址:1100 0000 1010
- 就可以根据逻辑地址写一些指令,如变量x至ACC寄存器,机器指令的结构为操作码+地址码(使用逻辑地址),指令为:000001 001000000011
- OS把这给程序成4页,每页1KB, 所以程序的地址结构是若干位逻辑页号和10位页内地址。程序的这一页可能对应主存的某一块,则这一块的主存块号+块内地址就是这个程序的物理地址。
- 为了记录逻辑页号和主存块号之间的关系,OS会建立一张页表,负责记录逻辑页号是存放在哪个主存块号中。
- CPU执行的机器指令中,使用的是“逻辑地址”,因此需要通过页表将逻辑地址转为物理地址。页表的作用:记录每个逻辑页面存放在哪个主存块中。
- 页表中的一行称为页表项,页表数据存在主存里。
- CPU中有一个页表基址寄存器,负责存放主存中页表的首地址。
- 由于程序的局部性原理,近期内可能翻出查询一个页表项,所以可以将近期访问的页表项放入更高速的存储器中,可加快地址变换的速度。
由此引入一个基于Cache的结构:快表(TLB) - 快表(TLB):CPU对快表的查询速度非常快。当查询TLB未命中时,可以把页表中的对应页表项复制到TLB中去。
- 快表是一种相联存储器:即CPU可以根据内容寻访。
3.6.2 虚拟存储器
上一小节提到的页表完成了逻辑页号和主存块号之间的映射,但是由于计算机启动时可能会有一些程序没有从辅存中复制到主存中,所以要对页表做一些改造:
- 页表包括逻辑页号、主存块号、外存块号、有效位、访问位、脏位。其中,有效位在主存块号有效时置一,否则为0;访问位是该页表项的访问计数器,在TLB满了需要替换的时候使用,脏位是标记这个页表项在主存中对应的数据是否被修改,1表示被修改,0表示未被修改。
- 页式虚拟存储器的结构示意图如下:
- 段式虚拟存储器:
页式虚拟存储器是将程序拆分成大小相等的页面。
段式虚拟存储器是按照功能模块将程序拆分成大小不同的页面。 - 用段式虚拟存储器的情况下主存地址就不分块了。段式虚拟存储器结构如下:
- 段页式虚拟存储器:
把程序按逻辑结构分段,每段再划分为固定大小的页,主存空间也划分为大小相等的页,程序对主存的调入、调出仍以页为基本传送单位。每一个程序对应一个段表,每段对应一个页表。虚拟地址:段号+段内页号+页内地址