存储系统 | CO
存储器概述
存储器的分类
按在计算机中的作用(层次)分类
主存储器 / 主存 / 内存储器 / 内存
用来存放计算机运行期间所需的程序和数据。
CPU 可直接随机地对其进行访问,也可以和高速缓冲存储器(Cache)及辅助存储器交换数据。
特点:容量较小、存取速度较快、每位的价格较高。
辅助存储器 / 辅存 / 外存储器 / 外存
用来存放当前暂时不用的程序和数据,以及一些需要永久保存的信息。
辅存的内容需要调入主存后才能被 CPU 访问。
特点:容量大、存取速度较慢、单位成本低。
高速缓冲存储器 Cache
位于 CPU 和主存之间,用来存放当前 CPU 经常使用的指令和数据,以便 CPU 能高速地访问它们。
特点:存取速度可与 CPU 的速度相匹配、存储容量小、价格高。
现代计算机通常将它们制作在 CPU 中。
按存储介质分类
磁芯存储器
磁表面存储器
磁盘、磁带。
半导体存储器
MOS 型半导体存储器
金属氧化物半导体 MOS (Metal Oxide Semiconductor)。
SRAM、DRAM、非易失型 MOS 存储器(ROM)。
读写速度慢、集成度高、功耗小。
双极型半导体存储器
读写速度快、集成度低、功耗大。
光存储器/光盘
光介质存储器。
按存取方式分类
随机存储器 RAM (Random Access Memory)
存储器任一单元的内容都可随机存取,且存取时间与存储单元的物理位置无关。
优点:读写方便、使用灵活、易失性。
主要用作主存或 Cache。
又分为静态随机存储器 SRAM 和动态随机存储器 DRAM。
同步动态随机存储器是现在最常用的一种 DRAM。
串行访问存储器(Serial Access Memory)
与 RAM 相对,访问存储单元时需按其物理位置的先后顺序寻址。又分为:
顺序存取存储器 SAM (Sequential Access Memory)
其内容只能按某种顺序存取,存取时间的长短与信息在存储体上的物理位置有关。
存取速度慢。
如磁带。
直接存取存储器 DAM (Direct Access Memory)
存取方式介于 RAM、SAM 之间,存取时通常先寻找整个存储器中的某个小区域(如磁盘上的磁道),再在小区域内顺序查找。
如磁盘、光盘。
只读存储器 ROM (Read-Only Memory)
特点:
- 只能读(随机读⚠,RAM 和 ROM 都采用随机访问方式)。
- 一旦写入就固定不变。
- 断电内容不丢失。
用途:
- 通常用于存放固定不变的程序、常数和汉字字库等。
- 与 RAM 可共同作为主存的一部分,统一构成主存的地址域。
注意:
- 广义上的 ROM 已可通过电擦除等方式进行写入,失去 “只读” 特性,保留了断点内容保留、随机读取特性,但写入比读取慢得多。
- 只读型光盘存储器 CD-ROM (Compact Disc ROM):只能写入一次。不属于 ROM。
按信息的可保存性分类
易失性存储器
断电后存储信息即消失,如 RAM。
非易失性存储器
断电后信息仍然保持,如 ROM、磁表面存储器、光存储器。
🌱破坏性读出
某个存储单元所存储的信息被读出时,原存储信息被破坏,称为破坏性读出(不会被破坏则称为非破坏性读出)。
具有破坏性读出性能的存储器,每次读出操作后,必须紧接一个再生的操作,以便恢复被破坏的信息。
存储器的性能指标
设计存储器系统所追求的目标:大容量、高速度、低成本。
存储容量
存储容量 = 存储字数 × 字长。
存储字数表示存储器的地址空间大小,字长表示一次存取操作的数据量。
存储速度
访问时间
从启动一次存储器操作到完成该操作所经历的时间,分为读出时间和写入时间。
读出时间 $T_A$:从存储器接到读命令开始至信息被送到数据线上所需的时间。
写入时间 $T_W$:从存储器接到写命令开始至信息被写入数存储器所需的时间。
存取周期 / 读写周期 / 访问周期 $T_M$
存储器进行一次完整的读/写操作所需的全部时间,也就是存储器进行连续读写操作所允许的最短间隔时间。
DMA 传送方式中的周期挪用方式中,I/O 设备挪用的就是存取周期。对 DMA 请求的响应,可以发生在指令执行过程中的任何两个存取周期之间。
存取时间 ≠ 存储周期:

对任何一种存储器,在读写操作后,由于读出放大器、驱动电路等都有一段稳定恢复时间,不能立即进行下一次访问;对于破坏性读出的存储器,需要的恢复时间比较长,甚至等于存取时间,因为存储器中的信息读出后需要马上进行再生。
带宽 / 数据传输率 $B_m$
表示存储器被连续访问时可以提供的数据传送速率,即每秒可从存储器进出信息的最大数量。
主存带宽 = 数据总线宽度/存取周期。
单位成本
每位价格 = 总成本/总容量。
多级层次的存储系统
为解决存储系统大容量、高速度和低成本相互制约的矛盾,在计算机系统中通常采用多级存储器结构。
存储器层次结构的主要思想:上一层的存储器作为低一层存储器的高速缓存。
以 “Cache-主存” 层次为例,从 CPU 的角度看,该层速度接近于 Cache,容量和位价却接近于主存 ,这就解决了速度、容量、成本三者之间的矛盾。
多级存储器结构

三级存储系统的层次结构

实际上存储系统层次结构主要体现在两个层次上:
Cache-主存
主要解决 CPU 和主存速度不匹配的问题。
数据调动由硬件自动完成,对所有程序员透明。
主存-辅存
主要解决存储系统的容量问题。
数据调动由硬件和操作系统共同完成,对应用程序员透明。
形成了虚拟存储系统,在这个系统中程序员编程的地址范围与虚拟存储器的地址空间相对应。对于具有虚拟存储器的计算机系统而言,编程时可用的地址空间远大于主存空间。
这两个层次中,上层内容只是下层内容的副本,即 Cache(主存)中的内容只是主存(辅存)中的内容的一部分。
主存与 CPU、Cache、辅存都能交换信息,而辅存需要通过主存与 CPU 交换信息。
现代计算机系统几乎都采用这种三级存储系统。
主存储器
主存储器的基本组成
记忆单元 Cell:也称为存储元、位元,存放一个二进制位的物理器件。
编址单位:也称为存储单元,主存中具有相同地址的那些位元构成一个存储单元,可以是一个字节或一个字。
存储阵列 Bank:也称为存储体、存储矩阵,所有存储单元构成一个存储阵列,是存储器的核心部分。

MAR 和 MDR 理论上属于主存,但现代计算机绝大多数集成于 CPU 中。
注意上图中有两个地址寄存器:主存地址寄存器 MAR 和主存中的地址寄存器(图源:袁)。
DRAM 芯片容量较大,地址位数较多,为了减少芯片的地址引脚数,通常采用地址引脚复用技术,行地址和列地址通过相同的引脚分先后两次输入,这样地址引脚数可减少一半。
内存通道 Channel、内存模块、Rank、Chip、Bank、Row/Column 的关系如下:

内存模块就是常说的内存条,目前常见的内存条都属于双列直插内存模块 DIMM (Dual Inline Memory Module),它的两个面都可作为一个独立的 Rank 各自传输信号。DIMM 位宽或者说 Rank 位宽为 64bit,即数据字长。一个 Rank 有 8 个黑色颗粒,我们把每个黑色颗粒叫做 Chip,即常说的内存颗粒,实际上就是一颗 DRAM 芯片。上图中的一颗 DRAM 芯片里又包含 8 个 Bank(也可以说是一个 Rank 包含 8 个 Bank),不过每次存取只会选中其中一个 Bank,因此 Bank 位宽即为 Chip 位宽。每个 Bank 又由若干位平面 Array 组成,同属一个 Bank 的 Array 的同行、同列的位元组成一个超元,会被同时存取。一个 Bank 包含的 Array 数量即为 Bank 的位宽,也即 Chip 的位宽。

内存通道 Channel 则是内存模块与内存控制器之间的数据传输路径,一条通道对应一组存储器总线和内存控制器。因此多通道存储器技术,意味着要有多组并行传输的存储器总线、处理器包含多个内存控制器以及主板上有多组内存条插槽。
补充:单列直插内存模块 SIMM (Single Inline Memory Module) 是一种两侧金手指提供相同信号的内存结构,故一块 SIMM 只存在一个 Rank,并且金手指还存在冗余。在内存发展进入 SDRAM 时代后,SIMM 逐渐被 DIMM 技术取代。
主存芯片技术
Cache 由 SRAM 实现,主存由 DRAM 实现。
主存芯片的内部结构
也即 DRAM 芯片的内部结构。

存储体芯片:存储体 + 外围电路(I/O 读写电路、地址译码和控制电路等)
目前 DRAM 芯片普遍采用双译码结构。地址译码器分为 X 和 Y 方向两个译码器,在选中的行列交叉点上能确定一个存储单元。这种方式可减少单个译码器的选通线的数量,使电路简单清晰。

存储体
存储体是存储单元的集合,由行选择线(X)和列选择线(Y)来选择所访问存储单元,存储体的相同行、列上的多位(位平面数)同时被读出或写入。
采用二维双译码结构的存储器芯片(即一个 Bank 只有一个位平面)被称为位片式芯片,因为其在选中的行和列交叉点上的单元只有一位。有些芯片采用三维结构,用多个位平面构成存储阵列(如上图,由 8 个位平面构成一个 Bank)。不同位平面在同一行、同一列交叉点上的多位构成一个存储字,称为超元(supercell),超元的各位被同时读入或写入。
地址译码器
将地址转换为译码输出线上的高电平,以便驱动相应的读/写电路。
I/O 控制电路
处于存储体与数据总线之间,用以控制被选中的单元的读出或写入,并具有放大信息的作用。
在双译码结构中加在 Y 译码器输出后。
驱动器
保持电信号稳定。
在双译码结构中,一条 X 方向的选择线要控制在其上的各个存储单元的字选择线,负载较大,因此需要在 X 译码器输出后加驱动器,由驱动器驱动连接在行方向选择线上的所有存储元电路。

读写控制信号
根据 CPU 给出的是读命令还是写命令,控制被选中单元进行读或写。
读写控制线可能有一根,也可能分开两根。
片选控制信号
在访问某个字时,用以 “选中” 该存储字所在的芯片。
地址寄存器
注意和 CPU 中的存储器地址寄存器 MAR 区分。
🚁示例:4M × 4 位 DRAM 芯片

上图是某 4M x 4 位 DRAM 芯片示意图。DRAM 芯片容量较大,因而地址位数较多。为了减少芯片的地址引脚数,从而减小体积,大多采用地址引脚复用技术。行地址和列地址通过相同的引脚分先后两次输入,这样地址引脚数可减少一半。
图 a 给出了芯片的引脚,共有 11 根地址引脚线 A$_{10}$A$_0$,在行地址选通信号 RAS 和列地址选通信号 CAS(低电平有效)的控制下,用于分时传送行、列地址;此外,有 4 根数据引脚线 D$_4$D$_1$,因此,每个芯片同时读出 4 位数据;WE 为读写控制引脚,低电平时为写操作;OE 为输出使能驱动引脚,低电平有效,高电平时断开输出。
图 b 给出了芯片内部的逻辑结构图,芯片存储阵列采用三维结构,芯片容量为 2048 × 2048 × 4 位,即,行地址和列地址各 11 位,有 4 个位平面,在每个行、列交叉处的 4 个位平面数据同时进行读写。🚩行地址缓冲器和刷新计数器通过一个多路选择器 MUX,将选择的行地址输出到行译码器,刷新计数器的位数也是 11 位,一次刷新相当于对一行数据进行一次读操作,通过对这一行数据读后再生进行刷新。
DRAM 的工作原理
存储元
存储元通常只使用一个晶体管(MOS 管)。

利用存储元电路中栅极电容上的电荷存储信息。
读出 1:MOS 管接通后,电容放电,数据线上产生电流(电容内存储电荷)。
读出 0:MOS 管接通后,数据线上无电流(电容内未存储电荷)。
电容放电信息被破坏,属于破坏性读出。
读出后应有重写操作,也称 “再生”,这也是称其为动态存储器的原因。
重写导致读写速度更慢。
相对于 SRAM 来说,DRAM 具有容易集成、位价低、容量大和功耗低等优点,但存取速度比 SRAM 慢,一般用于大容量的主存系统。
译码结构
采用地址复用技术,地址线、地址引脚数量减半,地址信号分行、列两次先后传送。
刷新
栅极电容上的电荷一般只能维持 1~2ms,即使不断电,信息也会自动消失,为此每隔一段时间必须对全部存储元电路进行刷新。
相邻两次刷新的时间间隔称为刷新周期,通常取 2ms。
刷新单位是行,由芯片内部自行生成行地址。
刷新时不需要选片,即整个存储器中的所有芯片同时被刷新。
刷新对 CPU 透明,即刷新不依赖于外部的访问。
刷新操作类似于读操作(假读,读但不输出数据),根据读出内容对相应单元进行重写,即读后再生。
一次刷新占用一个存储器存取周期(≠ 访存,因为没有在总线上输入输出)。
虽然 DRAM 的刷新和再生都是恢复数据,但刷新与再生的过程并不完全相同。刷新是以行为单位 + 整个存储器中的所有芯片一起,逐行恢复数据的;而再生仅需恢复被读出的那些单元的数据。
常用刷新方式(以刷新周期 2ms、存取周期 0.5μs、128×128 矩阵的存储芯片为例):
集中刷新
在一个刷新周期内,利用一段固定的时间,依次对存储器的所有行进行逐一再生。
在此期间停止对存储器的读写操作,称为 “死时间”,又称访存 “死区”。
优点:读写操作时不受刷新工作的影响。
缺点:在死区不能访问主存。
分散刷新
把对每行的刷新分散到各个工作周期中,即每个存取周期后绑定一次刷新
存取芯片的存取周期为 0.5 μs,系统的存取周期/工作周期为 1 μs。
优点:没有死区。
缺点:加长了系统存取周期,降低了整机的速度(刷新频率太高)。
异步刷新
每行每隔 2ms(刷新周期)刷新一次,即每隔 $\frac{刷新周期}{行数}=\frac{2000}{128}$μs 刷新一行。
优点:缩短死区(每 15.6μs 有 0.5 μs 的死区),使 “死时间” 的分布更加分散,避免使 CPU 连续等待过长的时间;减少刷新次数,从根本上提高了整机的工作效率。
DRAM 芯片行、列数的优化原则
假定有一个 $2^n × b$ 位 DRAM 芯片的存储阵列,其行数为 $r$,列数为 $c$,存储阵列的地址位数为 $n$,则:
$2^n=r×c$,行地址位数为 $\log_2{r}$,列地址位数为 $\log_2{c}$,$n=\log_2{r} + \log_2{c}$。
由于 DRAM 芯片采用地址引脚复用技术,为减少地址引脚数,应尽量使行、列位数相同,即满足 $|r-c|$ 最小。
又由于 DRAM 按行刷新,为减少刷新开销,应使行数较少,因此还需满足 $r \le c$。
行缓冲器
下图是一个 DRAM 芯片内部结构示意图。图中芯片容量为 16×8 位,存储阵列为 4 行 × 4 列,地址引脚采用复用方式,因而仅需 2 根地址引脚,在 RAS 和 CAS 的控制下分时传送 2 位行地址和 2 位列地址。每个超元(supercell)有 8 位,需 8 根数据引脚,有一个内部行缓冲(row buffer),用来缓存指定行中每一列(即一整行)的数据,其大小为列数 × 位平面数,通常用 SRAM 元件实现。
下图是 DRAM 芯片读写原理示意图。图 a 反映存储控制器在 RAS 有效时将行地址送到行译码器后选中第 “2” 行时的状态,此时,整个一行数据被送到内部行缓冲中。图 b 反映存储控制器在 CAS 有效时将列地址 “1” 送到列译码器后选中第 “1” 列时的状态,此时,将内部行缓冲中第 “1” 列的 8 位数据超元 (2, 1) 读到数据线,并继续向 CPU 传送。
基本 SDRAM 芯片技术
目前主存常用的是基于 SDRAM (Synchronous DRAM) 芯片技术的内存条,包括 DDR SDRAM、 DDR2 SDRAM、 DDR3 SDRAM 等。SDRAM 芯片与当年 Intel 推出的芯片组中北桥芯片的前端总线同步运行,因此称作同步 DRAM。
SDRAM 的工作方式与传统的 DRAM 有很大不同。传统 DRAM 与 CPU 之间采用异步方式交换数据,CPU 发出地址和控制信息后,经过一段延迟时间,数据才读出或写入。在这段时间里,CPU 不断采样 DRAM 的完成信号,在没有完成之前,CPU 陷入等待状态而不能做其他工作。而 SDRAM 不同,其读写受外部系统时钟(即前端总线 CLK)控制,因此与 CPU 之间采用同步方式交换数据。它将 CPU 或其他主设备发出的地址和控制信息锁存起来,经过确定的几个时钟周期后给出响应。因此,主设备在这段时间内可以安全地进行其他操作。
SDRAM 的每一步操作都在外部系统时钟 CLK 的控制下进行,支持突发传输方式。只要在第一次存取时给出首地址,以后按地址顺序读写即可,而不再需要地址建立时间和行、列预充电时间,就能连续快速地从行缓冲器中输出一连串数据。
内部的工作方式寄存器(也称模式寄存器)可用来设置传送数据的长度以及从收到读命令(与 CAS 信号同时发出)到开始传送数据的延迟时间等,前者称为突发长度 BL (BurstLength),后者称为 CAS 潜伏期 CL (CAS Latency)。根据所设定的 BL 和 CL,CPU 可以确定何时开始从总线上取数以及连续取多少个数据。在开始的第一个数据读出后,同一行的所有数据都被送到行缓冲器中,因此,以后每个时钟可从 SDRAM 读取一个数据,并在下一个时钟内通过总线传送到 CPU。
基于 SDRAM 技术的芯片的工作过程大致如下:
① 在 CLK 时钟上升沿片选信号 CS 和行地址选通信号 RAS 有效。
② 经过一段延时 $t_{RCD}$(RAS to CAS delay),列选通信号 CAS 有效,并同时发出读或写命令,此时,行、列地址被确定,已选中具体的存储单元。
③ 对于读操作,再经过一个 CAS 潜伏期后,输出数据开始有效,其后的每个时钟都有一个或多个数据连续从总线上传出,直到完成突发长度 BL 指定的所有数据的传送。对于写操作则没有 CL 延时而直接开始写入。
由于只有读操作才有 CL,所以 CL 又被称为读取潜伏期 RL (Read Latency)。$t_{RCD}$ 和 CL 都是以时钟周期 $T_{CK}$ 为单位,例如,对于 PC100 SDRAM 来说,当 $T_{CK}$ 为 10ns,CL 为 2 时,则 CAS 潜伏期时延为 20ns。BL 可用的选项为 1、2、4、8 等,当 BL 为 1 时,则是非突发传输方式。
SRAM 的工作原理
存储元使用双稳态触发器(6 个 MOS 管)来记忆信息。
双稳态:0(A 低 B 高)、1(A 高 B 低)。
读出数据,触发器状态保持稳定,属于非破坏性读出,无需重写,读写更快。
SRAM 集成度低,容量小,地址位数比较少,因此不采用地址复用,行列地址是同时送的。
SRAM 的存取速度快,但集成度低,功耗大,价格昂贵,一般用于高速缓冲存储器。
SRAM 比 DRAM 贵是因为制造 SRAM 需要更多的硅。
SRAM 和 DRAM 的比较
DRAM 芯片的读写周期
读周期
读出时间 $t_A$:从给出有效地址开始,到读出所选中单元的内容并在外部数据总线上稳定地出现所需的时间。
读周期时间 $t_{RC}$:存储芯片进行两次连续读操作所必须间隔的时间(≥ 读出时间)。在读周期内读写控制信号 $\overline{WE}$ 为高电平。
片选的保持时间 $t_{CO}$:地址片选信号 $\overline{CS}$ 必须保持低电平到数据稳定输出。
为使芯片能正确接受行、列地址并实现读/写操作,各信号的时间关系应符合一定要求。
行地址、列地址分别需要在行选通信号 $\overline{RAS}$、列选通信号 $\overline{CAS}$ 有效前送到芯片的地址引脚。其中,$\overline{CAS}$ 滞后 $\overline{RAS}$ 一段时间。
$\overline{RAS}$、$\overline{CAS}$ 应至少保持 $t_{RAS}$ 和 $t_{CAS}$ 的时间。
在读周期中,$\overline{WE}$ 为高电平,并在 $\overline{CAS}$ 有效前建立。
写周期
滞后时间 $t_{AW}$:地址有效后,必须经过 $t_{AW}$ 的时间,$\overline{WE}$ 才能有效(低电平)。
写入时间 $t_W$:$\overline{CS}$ 和 $\overline{WE}$ 相与的宽度至少为 $t_W$(都为低电平)。
写恢复时间 $t_{WR}$:$\overline{WE}$ 无效后,经 $t_{WR}$ 时间后地址才能改变,否则也可能错误地写入。
写周期时间/地址有效时间 $t_{WC}$:连续两次写操作之间的最小时间间隔。$t_{WC}=t_{AW}+t_{W}+t_{WR}$。
$t_{DW}$:写入数据必须在写无效之前 $t_{DW}$ 时间就送到数据总线上。
写周期中行列选通信号的时序关系和读周期相同。
为了保证数据可靠地写入,写数据必须在 $\overline{CAS}$ 有效前在数据总线上保持稳定。
在写周期中,$\overline{WE}$ 为低电平,同样要在 $\overline{CAS}$ 有效前建立。
存储器芯片的引脚
引脚组成:电源线、接地线、数据线、地址线、控制线。
DRAM 芯片引脚数量
- 电源线 ×1
- 接地线 ×1
- 数据线数量 = 存储单元位数(位平面数)
- 地址线数量 = $\frac{\log_{2}存储单元数量}{2}$
- 控制线:行通选线 ×1(代替片选线)、列通选线 ×1、读写控制线(默认 ×2)
SRAM 芯片引脚数量
- 电源线 ×1
- 接地线 ×1
- 数据线数量 = 存储单元位数(位平面数)
- 地址线数量 = $\log_{2}存储单元数量$
- 控制线:片选线 ×1、读写控制线(默认 ×2)
只读存储器
ROM 特点
- 结构简单,所以位密度比可读/写存储器的高。
- 具有非易失性,可靠性高。
- 支持随机访问。但不意味着它们可以作为随机存取存储器(写入时间过长,且改写次数有限)。
ROM 类型
掩模式只读存储器 MROM (Mask ROM)
厂家按客户要求,在芯片生产过程中直接写入信息,之后任何人不可重写(只能读出)。
优点:可靠性高,集成度高,价格便宜。
缺点:灵活性差。
一次可编程只读存储器 PROM (Programmable ROM)
可以实现一次性编程的只读存储器。
允许用户利用专门的设备(编程器)写入,一旦写入,内容无法改变。
可擦除可编程只读存储器 EPROM (Erasable Programmable ROM)
可进行多次改写。
无法取代 RAM,因为 EPROM 编程次数有限,且写入时间过长。
紫外可擦除可编程只读存储器 UVEPROM (Ultra-Violet Erasable Programmable ROM)
用紫外线照射 8~20 分钟,擦除所有信息。
电可擦除可编程只读存储器 EEPROM (Electrically Erasable Programmable ROM)
用电擦除重写。
闪存(Flash Memory)
EEPROM 的变种,能在字节水平上进行删除和重写(EEPROM 是整个芯片擦写),且擦除重写的速度快。
兼有 ROM 和 RAM 的优点,可在不加电的情况下长期保存信息,又能在线进行快速擦除与重写。
每个存储元只需单个 MOS 管,位密度高。
写入前要先擦除,因此写比读慢。
固态硬盘 SSD (Solid State Drives)
用固态电子存储芯片阵列制成的硬盘,由控制单元和存储单元(Flash 芯片)构成,与闪存的主要区别在于控制单元不一样。
保留了 Flash 存储器长期保存信息、快速擦除与重写的特性,对比传统硬盘也具有读/写速度快、低功耗的特性。
缺点是价格较高。
手机辅存也使用 Flash 芯片,但相比 SSD 使用的芯片集成度更高、功耗更低、价格更贵。
BIOS (Basic Input/Output System) 芯片
主板上的 ROM 芯片,BIOS 程序固化在其中。
逻辑上,主存由 RAM+ROM(BIOS) 组成,且二者常统一编址。
提高访存速度的措施
单体多字存储器
在单体多字系统中,每个存储单元存储了 $m$ 个字,数据总线宽度也为 $m$ 个字。按地址在一个存取周期内可一次并行读出 $m$ 个字的指令或数据,使主存带宽提高到 $m$ 倍。
优点:增大了存储器的带宽,提高了单体存储器的工作速度。
缺点:指令和数据在主存内必须连续存放时才能有效提升存取速度。一旦遇到转移指令,或操作数不能连续存放,这种方法的效果就不明显。
单体多字 vs 位扩展:二者从原理上可视为同一个概念。不过单体多字貌似可以通过对单个芯片增加位平面数来实现。
单体多字 vs 低位交叉编址同时启动:。
多体并行存储器
多体并行存储器由多体模块组成(单根内存条多个芯片 or 多根内存条),属于空间并行技术。
各模块容量和存取速度(主频)相同。不同也不是不行,只是不能完全实现并行和发挥性能(木桶效应)。
各模块都有独立的读写控制电路、地址寄存器和数据寄存器。
各模块既能并行工作,又能交叉工作。
多体并行存储器分为高位交叉编址和低位交叉编址两种。
高位交叉编址(顺序方式)
高位地址为体号,低位地址为体内地址。
理论上多个存储模块可以并行访问,但通常都是连续访问,因而不能提高存储器的吞吐率。
实际效果相当于单纯的扩容,存取方式仍是串行存取,因此这种存储器仍是顺序存储器。
低位交叉编址(交叉方式)
低位地址为体号,高位地址为体内地址,$m$ 个模块按 “模 $m$” 交叉编址。
程序连续存放在相邻模块中,因此称采用此编址方式的存储器为交叉存储器。
可在不改变每个模块存取周期的前提下,采用流水线方式并行存取(宏观),提高存储器的带宽。
交叉存储器中的各模块既能交叉工作,又能并行工作,对应两种启动方式:
轮流启动方式
设模块存取周期为 $T$,总线周期为 $r$。为实现轮流启动方式(流水线不间断),应保证模块数 $m ≥ T/r$。
宏观上,一个存取周期内,$m$ 体交叉存储器可以提供的数据量为单个模块的 $m$ 倍。
当 $m ≥ T/r$ 时,连续访问 $n$ 个存储字,耗时 $T+(n-1)r$。
🌱访存冲突:在某个模块上一个存取周期尚未结束的情况下进行再次访问。在 $m = T/r$ 的情况下体现为,给定的访存地址在相邻的 $m$ 次访问中出现在同一个存储模块内。
408 默认 $m = T/r$。
同时启动方式
即同时启动所有模块进行并行读/写。
数据总线位数 = 模块存储字长 × 模块数 $m$,模块存储周期 $T$ = 总线周期 $r$,即每个总线周期传输的数据变成 $m$ 倍存储字。
⚠特别注意
408 默认交叉编址为低位交叉编址。
考试时通常需要自行判断是轮流启动还是同时启动:如果每个存储模块存储字位数和存储器总线中的数据位数相等,则是轮流启动;若所有存储模块一次并行读写的总位数正好等于存储器总线中的数据位数,则可以采用同时启动方式。
另外,存取周期/存取时间与总线周期没有必然联系。前者是对于存储器而言,后者是对于总线而言。从大小上说,一般是存取周期 > 总线周期 > 存取时间的,这就使得 CPU 不能连续得存取数据,只能等待。要想让 CPU 连续存取,一般是采用多存储器交叉工作的方式。
多通道存储器
现在的计算机中可以有多组存储器总线同时进行数据传输。一组存储器总线对应一个内存通道,理论上 $n$ 通道存储总线的总带宽可以达到单通道的 $n$ 倍。
多体并行技术与多通道技术常常结合使用,所以在主板上按照内存条时,插入插槽的位置是有讲究的。在支持双通道并且有四个内存条插槽的主板上,每个内存通道对应两个内存条插槽,在安装两根内存条时,显然要分别插入对应不同通道的插槽上才能实现双通道内存(一般是插入颜色相同的两个插槽),如果只是将两根内存条插在同一组存储器总线上,则只属于多体并行存储器。
双口存储器
双口存储器在一个存储器中提供两组独立的读写控制电路和两个读写端口,因而可以同时提供两个数据的并行读写,是一种空间并行技术。
下图是一个双口存储器逻辑结构示意图。每个读写口都有一套独立的地址缓存器和译码电路,两套电路并行独立工作。当 A、B 两个端口地址不相同时,可以向存储体一次读写两个单元的内容;当 A、B 两个端口地址相同时,发生冲突(除了同时读),可按照特定的优先顺序选择其中一个端口进行读写。
通常用双口 RAM 作为通用寄存器组 GRS 或指令预取部件,也有一些计算机把双口 RAM 设计成一个端口面向 CPU,另一个端口面向输入输出(如 I/O 处理器或 DMA 设备)。也可以将其用在多机系统中,实现双口或多口存储器与多 CPU 之间的信息交换。
主存储器与 CPU 的连接
连接原理
如上图所示,内存条插槽就是存储器总线,内存条中的信息通过内存条的引脚,再通过插槽内的引线连接到主板上,通过主板上的导线连接到北桥芯片或 CPU 芯片。
在传统的三芯片结构(CPU + 北桥 + 南桥)中,CPU 通过处理器总线(前端总线)和存储器总线与主存相连,处理器总线和存储器总线通过一个 I/O 桥接器(即北桥芯片)相连:
Intel 推出 Core i7 时,北桥芯片的功能被集成到了 CPU 芯片内,也就是说 Core i7 及以后的处理器芯片中集成了内存控制器,因而存储器总线直接连接到 CPU,CPU 通过存储器总线直接和内存条相连。
存储器总线作为系统总线,可进一步分为数据总线、地址总线和控制总线:
数据总线的位数与工作频率的乘积正比于数据传输率。
地址总线的位数决定了可寻址的最大内存空间。
控制总线(读/写)指出总线周期的类型和本次输入/输出操作完成的时刻。
存储器芯片的输入输出信号:
存储器芯片的扩展
受集成度和功耗等因素的限制,单个芯片的容量不可能很大,所以往往通过存储器芯片扩展技术,将多个芯片做在一个内存模块(即内存条)上,然后由多个内存模块以及主板或扩充板上的 RAM 芯片和 ROM 芯片组成一台计算机所需的主存空间,再通过总线、桥接器等和 CPU 相连。
由若干个存储器芯片构成一个存储器时,需要在字方向和位方向上进行扩展,以满足实际存储器的容量要求。
32K × 16 位存储芯片,意味着该芯片存储字数 32K、存储字长 16 位。
若题目在说明存储芯片不是以 “字数 × 字长” 形式给出的,如 16KB,且根据题干和选项也推测不出时,则默认存储字长为 8 位,即 16K × 1B。位扩展法
指用若干片位数较少的存储器芯片构成给定字长的存储器。
连接方式:各芯片的地址线、片选线和读/写控制线与系统总线相应并联;各芯片的数据线单独引出,分别连接系统数据线。各芯片同时工作。
下面两个图是用 8 个 8K × 1bit 的 DRAM 芯片扩展构成一个 8K × 8bit 内存条的示意图。
仅采用位扩展时,各芯片连接地址线的方式相同,但连接数据线的方式不同,在某一时刻会选中所有的芯片,所以片选信号 $\overline{\text{CS}}$ 要连接到所有芯片。
下图是用 8 个 16M × 8 位的 DRAM 芯片扩展构成一个 16M × 64bit = 128MB 内存条的示意图。每片 DRAM 芯片中有一个 4096 × 4096 × 8 位的存储阵列,所以,行地址和列地址各 12 位(2$^{12}$ = 4096),有 8 个位平面,即超元长度为 8bit。
内存条通过存储器总线连接到存储控制器,CPU 通过存储控制器对内存条中的 DRAM 芯片进行读写,CPU 要读写的存储单元地址通过总线被送到存储控制器,然后由存储控制器将存储单元地址转换为 DRAM 芯片的行地址 $i$ 和列地址 $j$,分别在行地址选通信号 RAS 和列地址选通信号 CAS 的控制下,通过 DRAM 芯片的地址引脚,分时送到 DRAM 芯片内部的行地址译码器和列地址译码器,以选择行、列地址交叉点 ($i$, $j$) 的 8 位数据(超元)同时进行读写,8 个芯片就可同时读取 64 位,组合成总线所需要的 64 位传输宽度,再通过存储器总线进行传输。
现代通用计算机大多按字节编址,因此,在上图所示的存储器结构中,同时读出的 64 位可能是第 0~7 号存储单元、第 8~15 号存储单元、…、第 8k~8k+7 号存储单元,以此类推。因此,如果访问的一个 int 型数据不对齐,假定在第 6、7、8、9 这四个存储单元中,则需要访问两次存储器;如果数据对齐的话,即起始地址是 4 的倍数,则只要访问一次即可。这就是数据需要对齐的原因。
64 位数据线 CPU 和一根 32 位内存条可以通过以下方式实现一起工作:
- 数据分割:64 位 CPU 在读取 32 位内存条数据时,会分成两次进行,即每次读取 32 位数据。这样做虽然可以工作,但会稍微影响性能。
- 总线频率调整:系统可能会调整总线频率以匹配内存条和 CPU 的数据传输需求,从而保证兼容性和稳定性。
- 内存控制器:现代 CPU 有内置的内存控制器,可以处理不同规格的内存模块,确保它们能正确协同工作。
而 32 位数据线的 CPU 和 64 位内存条无法直接一起工作,因为它们在设计和架构上的不兼容性。但现代内存控制器可以在一定程度上帮助解决这个问题。控制器会将 64 位内存条的数据分成 32 位的数据块,以适应 32 位 CPU 的数据处理能力。这种分割和适配虽然可以工作,但无法充分发挥 64 位内存条的全部性能。
注意上述两种情况内存条和 CPU 的连接,中间必须都通过桥接器或者内存控制器。
具体能否实现还是要看 CPU 和主板(提供的插槽规格和数量)是否同时支持。注意,由于内存总线都是并行传输信号的,所以无法实现将 32 位内存条插到 64 位内存条插槽上工作。而 PCIe 可以插到更宽的插槽是因为 PCIe 总线是串行传输的。
第一种情况如果无法实现,那就要利用多体并行技术(低位交叉同时启动方式)。
字扩展法
字扩展是容量的扩充,位数不变。即对存储字的数量进行扩展,而存储字的位数满足系统要求(系统数据线位数等于芯片数据线位数,系统地址线位数多于芯片地址线位数)。
连接方式:各芯片的地址线与系统地址线的低位对应相连;由系统地址线的高位译码得到各芯片的片选信号;各芯片的数据线和读/写控制线与系统总线相应并联。各芯片分时工作。
优点:地址空间可连续。
缺点:电路复杂。
字位同时扩展法
当芯片在容量和位数上都不满足存储器要求的情况下,需要对字和位同时扩展。
既增加存储字的数量,又增加存储字长,是前两种扩展的组合。
连接方式:将进行位扩展的芯片作为一组,各组的连接方式与位扩展的相同;由系统地址线高位译码产生若干片选信号,分别接到各组芯片的片选信号。
存储芯片的地址分配和片选
片内字选通常是由 CPU 送出的 $N$ 条低位地址线完成的,它们直接接到所有存储芯片的地址输入端($N$ 由片内字数 $2^N$ 决定)
片选信号的产生分为线选法和译码片选法
线选法
用除片内寻址外的高位地址线直接分别接至各个存储芯片的片选端。
这些片选地址线每次寻址只能有一位有效(为 0 有效),这样才能保证每次只选中一个芯片或芯片组。
优点:不需要地址译码器,线路简单。
缺点:地址空间不连续,选片的地址线必须分时为低电平(否则不能工作),不能充分利用系统的存储器空间,造成地址资源的浪费。
译码片选法
用除片内寻址外的高位地址线通过地址译码器芯片产生片选信号。
补充:译码器
存储器与 CPU 的连接
合理选择存储芯片
主要指存储芯片的类型(RAM 或 ROM)和数量的选择。
通常选用 ROM 存放系统程序、标准子程序和各类常数,RAM 则是为用户编程而设置的。
在考虑芯片数量时,要尽量使连线简单、方便。
地址线的连接
CPU 的地址线数往往比存储芯片的地址线数要多。
通常将 CPU 地址线的低位与存储芯片的地址线相连,以选择芯片中的某一单元(字选)。这部分的译码是由芯片的片内逻辑完成的。
CPU 地址线的高位则在扩充存储芯片时使用,用来选择存储芯片(片选)。这部分译码由外接译码器逻辑完成。
实际的主存容量不能代表 MAR 的位数,考虑到存储器扩展的需要,MAR 应保证能访问到整个主存地址空间,因此是 MAR 的位数决定了主存地址空间的大小。
数据线的连接
CPU 的数据线数与存储芯片的数据线数不一定相等。
在相等时可直接相连,在不等时必须对存储芯片扩位,使其数据位数与 CPU 的数据线数相等。
读/写命令线的连接
读/写命令线为一根时直接与存储芯片的读/写控制端相连,通常高电平读、低电平写。
读/写命令线分开时,读为 $\overline{RD}$,写为 $\overline{WE}$,均为低电平有效,此时 CPU 的读命令线与存储芯片的允许读控制端相连,写命令线与存储芯片的允许写控制端相连。
片选线的连接
存储器由许多存储芯片叠加而成,哪一片被选中完全取决于该存储芯片的片选控制端 $\overline{CS}$ 是否能接收到来自 CPU 的片选有效信号。
片选有效信号与访存控制信号 $\overline{MREQ}$ 有关(低电平有效),因为只有当 CPU 要求访存时才要求选中存储芯片。
若 CPU 访问 I/O,则 $\overline{MREQ}$ 为高,表示不要求存储器工作。
CPU 可使用译码器的使能端控制片选信号的生效时间。
外部存储器
磁盘存储器
磁盘存储器是以磁盘为存储介质的存储器。
优点
- 存储容量大,位价格低。
- 记录介质可重复使用。
- 记录信息可长期保存而不丢失,甚至可脱机存档。
- 非破坏性读出,读出时不需要再生。
缺点
- 存取速度慢。
- 机械结构复杂。
- 对工作环境要求较高。
磁盘设备的组成
磁盘存储器的组成
磁盘存储器由 磁记录介质 + 磁盘驱动器 + 磁盘控制器 三大部分组成。
磁盘控制器
磁盘驱动器与主机的接口,负责接收并解释 CPU 发来的命令,向磁盘驱动器发出各种控制信号,并负责检测磁盘驱动器的状态。
包括控制逻辑、时序电路、“并→串” 转换和 “串→并” 转换电路。
磁盘存储器是高速外设,所以磁盘控制器和主机之间采用成批数据交换方式。
主流的标准有 IDE、SCSI、SATA、PCIe 等。
磁盘驱动器
驱动磁盘转动并在盘面上通过磁头进行读/写操作的装置。
包括读写电路、读/写转换开关、读/写磁头与磁头定位伺服系统。
核心部件是磁头组件和盘片组件。每个盘面对应一个磁头,所有磁头固定在一起,与磁盘中心的距离相同且一起移动。
磁盘驱动器向盘片磁道记录数据时采用串行⚠方式写入。
磁盘驱动器除了具有读取数据、控制磁头等作用外,还能映射扇区和磁盘块的关系。
磁盘类型
- 固定头磁盘:磁头相对于盘片的径向方向固定,每个磁道一个磁头。
- 活动/可移动头磁盘:磁头可移动,磁头臂可来回伸缩定位磁道。
- 固定盘磁盘:永久固定在磁盘驱动器内。
- 可换盘磁盘:可移动和替换。
温彻斯特盘(简称温盘)是一种可移动磁头固定盘片的磁盘存储器,它是几乎所有现代硬盘产品的原型。
磁盘驱动器的内部逻辑(了解)
磁盘读写是指根据主机访问控制字中的盘地址(柱面号、磁头号、扇区号)读写目标磁道中的指定扇区。因此,其操作可归纳为寻道、旋转等待和读写三个步骤。如下图所示的操作过程如下。
寻道操作
磁盘控制器把盘地址送到磁盘驱动器的磁盘地址寄存器后,便产生寻道命令,启动磁头定位伺服系统,根据磁头号和柱面号,选择指定的磁头移动到指定的柱面。此操作完成后,发出寻道结束信号给磁盘控制器,并转入旋转等待操作。
旋转等待操作
盘片旋转时,首先将扇区计数器清零,以后每来一个扇区标志脉冲,扇区计数器加 1,把计数内容与磁盘地址寄存器中的扇区地址进行比较,如果一致,则输出扇区符合信号,说明要读写的信息已经转到磁头下方。
读写操作
扇区符合信号送给磁盘控制器后,磁盘控制器的读写控制电路开始动作。如果是写操作,就将数据送到写人电路,写人电路根据记录方式生成相应的写电流脉冲;如果是读操作,则由读出放大电路读出内容送磁盘控制器。
存储区域
一块硬盘含有若干记录面,每个记录面划分为若干圆形的磁道,每条磁道划分为若干扇区(也称盘块),扇区是磁盘读写的最小单位。
- 磁头数(Heads):即记录面数,表示磁盘共有多少个磁头,磁头用于读取/写入盘片上记录面的信息,一个记录面对应一个磁头。
- 柱面数(Cylinders):表示硬盘每面盘片上有多少条磁道。在一个盘组中,不同记录面的相同编号(位置)的诸磁道构成一个圆柱面。
- 扇区数(Sectors):表示每条磁道上有多少个扇区。
每个磁道与磁头一样宽,一个盘面有上千个磁道,磁道又划分为几百个扇区,扇区是磁盘可寻址的最小单位。
低密度存储方式下,扇区按固定圆心角度划分,所有磁道上的扇区数相同,且所有扇区容量一致,所以位密度从最外道向最里道增加,因而磁盘的存储能力受限于最内道的最大记录密度。
相邻磁道及相邻扇区间通过一定的间隙分隔开,以避免精度错误。
块/簇
绝大多数操作系统为改善磁盘访问时间,以簇/块为单位进行空间分配(Windows 下叫簇,Linux 下叫块),一簇/块包含 $2^n$ 个扇区。
操作系统(文件系统)以块/簇来为基本单位操作数据,而扇区是磁盘读写的基本单位。
为了更高效地管理磁盘,一块/簇最多只能存放属于一个文件的内容(即使文件大小小于一簇,甚至是 0 字节,也要占用一簇的空间),文件所占用的空间只能是簇的整数倍。
磁记录原理
原理
磁头和磁性记录介质相对运动时,通过电磁转换完成读/写操作。
编码方法
按某种方案(规律),把一连串的二进制信息变换成存储介质磁层中一个磁化翻转状态的序列,并使读/写控制电路容易、可靠地实现转换。
磁记录方式
通常采用调频制 FM 和改进型调频制 MFM 的记录方式。
磁盘的性能指标
记录密度
盘片单位面积上记录的二进制的信息量,通常以道密度、位密度和面密度表示
道密度:沿磁盘半径方向单位长度上的磁道数。
位密度:磁道单位长度上能记录的二进制代码位数。
面密度:位密度和道密度的乘积。
下图是磁盘盘面上的道密度和位密度示意图。左边采用的是低密度存储方式,所有磁道上的扇区数相同,所以每个磁道上的位数相同,因而内道上的位密度比外道位密度高;右边采用的是高密度存储方式,每个磁道上的位密度相同,所以外道上的扇区数比内道上扇区数多,因而整个磁盘的容量比低密度盘高得多。
磁盘容量
一个磁盘所能存储的字节总数,有非格式化容量和格式化容量之分。
非格式化容量:磁记录表面可以利用的磁化单元总数,由道密度和位密度计算而来。
格式化容量:按照某种特定的记录格式所能存储信息的总量。格式化后的实际容量只包含数据区。格式化后的容量比非格式化容量要小。
对于低密度存储方式,因为每个磁道的扇区数也即容量相等,所以其容量的计算方法为:
非格式化容量 = 记录面数 × 柱面数 × 每条磁道的磁化单元数
格式化容量 = 记录面数 × 柱面数 × 每道扇区数 × 每个扇区的容量
平均存取时间
磁盘响应读写请求的过程如下:首先将读写请求在队列中排队,出队列后由磁盘控制器解析请求命令,然后(由磁盘驱动器)进行寻道、旋转等待和读写数据三个过程,即:
平均存取时间 = 排队延迟 + 控制器时间 + 寻道时间 + 旋转延迟时间 + 传输时间。
磁盘上的信息以扇区为单位进行读写,上式中后面三个时间之和称为存取时间,即:
存取时间 = 寻道时间 + 旋转等待时间 + 数据传输时间。
- 寻道时间:指磁头移动到指定磁道所需时间。
- 旋转等待时间:指要读写的扇区旋转到磁头下方所需要的时间。
- 数据传输时间:指传输一个扇区的时间(大约 0.01ms/扇区)。若题目给了磁盘传输速率,就按磁盘传输速率算,不然就按旋转一个扇区的时间来算。
由于磁头原有位置与要寻找的目的位置之间远近不一,故寻道时间和旋转等待时间只能取平均值。
寻道时间取决于磁盘调度算法;平均旋转等待时间一般取磁盘旋转一周所需时间的一半,大约 4~6ms。假如磁盘转速为 6000 转/分,则平均旋转等待时间约为 5ms。因为数据传输时间相对于寻道时间和等待时间来说非常短,所以磁盘的平均存取时间通常近似等于平均寻道时间和平均旋转等待时间之和。
旋转等待时间只能取平均值,是针对某个扇区而言。若站在存取一个文件的角度,那么旋转等待时间就与文件的物理结构有关,可以说旋转等待时间的多少取决于磁盘空闲空间的分配程序。
数据传输率 $D_r$
指磁表面存储器完成磁头定位和旋转等待以后,单位时间内从存储介质上读出或写入的二进制信息量。
为区别于外部数据传输率,通常称之为内部传输速率,也称为持续传输速率。而外部传输速率是指主机中的外设控制接口从(向)外存储器的缓存读出(写入)数据的速度,由外设采用的接口类型决定。通常称外部传输速率为突发数据传输速率或接口传输速率。
由于磁盘在同一时刻只有一个磁头进行读写,所以内部数据传输速率等于单位时间内磁头划过的磁道弧长乘以位密度,即:
$D_r=rN$(磁盘转速 r 转/秒,每条磁道容量为 N 字节)
磁盘地址
磁盘地址 CHS:柱面号 • 盘面号 • 扇区号,注意次序。
磁盘阵列
独立冗余磁盘阵列 RAID (Redundant Array of Independent Disks)
指将多个独立的物理磁盘组成一个独立的逻辑盘,数据在多个物理盘上分割交叉存储、并行访问,具有更好的存储性能、可靠性和安全性。
RAID 的分级
RAID0(无冗余和无校验的磁盘阵列)
只实现了条带化和并行访问。
优点:数据存取快;容量大,充分利用磁盘空间,利用率为 100%。
缺点:不提供数据冗余,存在单点故障;不可靠,无数据检验,不能保证数据的正确性
磁盘条带化:把连续多个数据块交替地存放在不同物理磁盘的(相同位置的)扇区中,几个磁盘交叉并行读写,不仅扩大了存储容量,还能将 I/O 的负载均衡到多个物理磁盘上,提高磁盘数据存取速度。
RAID1(镜像磁盘阵列)
每个磁盘都具有一个对应的镜像盘。
磁盘与其镜像盘同时进行读写,互为备份。
磁盘阵列中单位成本最高,磁盘利用率最低,但提供了很高的数据安全性和可用性。
RAID2(采用纠错的海明码的磁盘阵列)
RAID0 优化版本,采用海明码校验(纠正一位错误并检测双位错误)。
数据会被分割包上校验并列写入各盘。海明码在磁盘陈列中被间隔写入到磁盘上,而且地址都一样,也就是在各个磁盘中,其数据都在相同的磁道及扇区中。
RAID3(位交叉奇偶校验的磁盘阵列)
类似于 RAID2,采用位交叉奇偶检验,只需一个冗余的校验磁盘。
RAID4(块交叉奇偶校验的磁盘阵列)
采用块奇偶检验,类似于 RAID3,不同的是,在数据分割上 RAID3 对数据的访问按位进行,而 RAID4 以数据块为单位。
RAID5(无独立校验的奇偶校验磁盘阵列)
类似于 RAID4,不同之处在于 RAID5 把奇偶校验条带分布在所有磁盘中
RAID6
与 RAID5 相比,增加了第二个独立的奇偶校验信息块,双重奇偶校验(P+Q)。
除 RAID0 外,无论何时有磁盘损坏,都可以拔出受损的磁盘再插入好的磁盘,而数据不会损坏,提高了系统的可靠性。
总之,RAID 通过同时使用多个磁盘,提高了存储容量和传输率;通过在多个磁盘上并行存取来大幅提高存储系统的数据吞吐量;通过镜像功能,提高安全可靠性;通过数据校验,提供容错能力。
固态硬盘 SSD
固态硬盘的特性
基于闪存技术,属于电可擦除 ROM(EEPROM),与 U 盘无本质区别,只是容量更大,存取性能更好。
一个 SSD 由一个或多个闪存芯片和闪存翻译层组成:
闪存芯片替代传统旋转磁盘中的机械驱动器;而闪存翻译层扮演了磁盘控制器的角色,通过电路将来自 CPU 的逻辑块读/写请求迅速翻译成对底层物理设备的读写/控制信号(逻辑块号 → 页)。
SSD 中一个闪存芯片由若干个区块组成,每个区块由若干页组成。通常,页大小为 512B ~ 4KB,每个区块由 32 ~ 128 页组成,因而区块大小为 16KB ~ 512KB。
以页为单位读写;干净的页才能写;以块为单位擦除,一旦擦除一块,块中的每页就可再写一次;某一区块进行若干次重复写之后,就会被磨损而变成坏的区块,不能再被使用。
随机写慢的原因
SSD 支持随机访问,但随机写慢,有两个原因:
- 擦除块比较慢,1ms 级,通常比访问页高一个数量级。
- 若写操作试图修改包含数据的页 P$_i$,那么这个块中所有含有有用数据的页都必须被复制到另一个新块中(被擦除过的),更新相应的逻辑与物理的映射关系,然后再进行对页 P$_i$ 的写操作。
虽然 SSD 的写速度慢于读速度,但不至于比传统机械硬盘差。
SSD 特点(与传统磁盘相比)
- SSD 由半导体存储器构成,用电路控制访问位置,没有移动的部件,读写速度快,随机访问性能高;机械硬盘通过移动磁臂旋转磁盘控制访问位置,有寻道时间和旋转延迟。
- SSD 安静无噪无振动、耐摔抗震、能耗低、安全、温度适应性好。
- SSD 容易磨损。SSD 的一个块擦多了(重复写)可能会磨损坏掉,而机械硬盘的扇区不会。
- SSD 造价高,但随着技术的不断发展,价格会不断下降,SSD 会逐步取代传统机械硬盘。
磨损均衡 Wear Leveling
SSD 的闪存翻译层中有一个专门的均化磨损(wear leveling)逻辑电路,试图将擦除操作平均分布在所有区块上,以最大限度地延长 SSD 的使用寿命。
SSD 磨损均衡技术大致分两种:
动态磨损均衡
写入数据时,优先选择累计擦除次数少的新闪存块。
静态磨损均衡
这种技术更为先进,就算没有数据写入,SSD 也会监测并自动进行数据分配、迁移,让老旧的闪存块承担无须写数据的存储任务,同时让较新的闪存块腾出空间,平常的读/写操作在较新的闪存块中进行。
有了这种算法加持,SSD 的寿命就比较可观了。例如,对于一个 256GB 的 SSD,若闪存的擦写寿命是 500 次,则需要写入 125TB 数据,才寿终正寝。就算每天写入 10GB 数据,也要三十多年才能将闪存磨损坏,更何况很少有人每天往 SSD 中写入 10GB 数据。
有些无良小作坊直接用普通闪存组装 SSD,这就使得读/写数据时会集中在 SSD 的一部分闪存,这部分闪存的寿命会损耗得特别快。一旦这部分闪存损坏,整块 SSD 也就损坏了。这种磨损不均衡的情况,可能会导致一块 256GB 的 SSD,只因数兆字节空间的闪存损坏而整块损坏。
高速缓冲存储器
程序访问的局部性原理
在程序的执行过程中,对信息的访问是不均匀的。
时间局部性:在最近的未来要用到的信息,很可能是现在正在使用的信息。
空间局部性:在最近的未来要用到的信息,很可能与现在正在使用的信息在存储空间上是临近的,因为指令通常是顺序存放、顺序执行的,数据一般也是以向量、数组等形式簇聚在一起的。
高速缓冲技术利用程序的局部性原理,把程序中正在使用的部分存放在一个高速的、容量较小的 Cache 中,使 CPU 的访存操作大多数针对 Cache 进行,从而大大提高程序的执行速度。
Cache 的基本工作原理
Cache 基本结构
Cache 和主存都被划分为相等的块,每块由若干字节组成(Cache 中的块也称为行)。
Cache 仅保存主存中最活跃的若干块的副本。
行长太小,不能充分利用程序访问的空间局部性;行长太大,失效损失变大(若未命中,则需花更多时间从主存读块)。
CPU 与 Cache/主存间信息交互的单位是字,而 Cache 与主存间信息交互的单位是块/行⚠。
Cache-主存系统的访存过程
CPU 发出读请求时
若访存地址在 Cache 命中,就将此地址转换成 Cache 地址,直接对 Cache 进行读操作,与主存无关;
若 Cache 不命中,则仍需访问主存,并把此字所在的块一次性地从主存调入 Cache。若此时 Cache 已满,则需根据某种替换算法,用这个块替换 Cache 中原来的某块信息。
CPU 发出写请求时
涉及主存块和 Cache 块的数据一致性问题,需要按照一定的写策略处理。
若 Cache 命中,常见的处理方法有全写法和写回法。
若 Cache 不命中,常见的处理方法有写分配法和写不分配法。
整个过程全部由硬件实现。
相关计算
Cache 的命中率 $H$
CPU 欲访问的信息已在 Cache 中的比率。
Cache-主存系统的平均访问时间 $T_a$ 的计算
设 $t_c$ 为访问一次 Cache 所需时间,$t_m$ 为访问一次主存所需时间。
不同访问方式有着不同的计算公式:
先访问 Cache,发现未命中再访问主存
$T_a=Ht_c+(1−H)(t_c+t_m)$
同时访问 Cache 和主存,若 Cache 命中则停止访问主存
$T_a=Ht_c+(1−H)t_m$
TLB 和慢表的平均访问时间与之类似,但要注意最后需要加上最后访问数据/指令的时间。
具有 TLB 和 Cache 的系统的平均访问时间会算吗😏。
行长与命中率的关系
行长较大,可以充分利用程序访问的空间局部性,使一个较大的局部空间被一起调到 Cache 中,因而可以增加命中机会。
但行长过大会使得 Cache 行数过少,命中的可能性反而降低;同时行长大使失效损失变大,也就是说,若未命中,则需花更多时间从主存读块。
Cache 和主存的映射方式
把主存地址空间映射到 Cache 地址空间,即把存放在主存中的信息按照某种规则装入 Cache。
由于 Cache 行数比主存块数少得多,因此 主存中只有一部分块的信息可放在 Cache 中:
- 给每个 Cache 行增加一个标记,指明它是主存中哪一块的副本。
- 每个 Cache 行还需要一个有效位,以说明该行中的信息是否有效。
地址映射的方法有三种:
直接映射
Cache 行号 = 主存块号 mod Cache 总行数。
Cache 地址 = 行号 + 行内地址。
对于容量为 $2^n$ 字节、总行数为 $2^m$ 行的 Cache,主存地址的低 $n$ 位为 Cache 地址,而这 $n$ 位地址的高 $m$ 位为 Cache 行号。
标记位数 = $\log_{2}{\frac{主存容量}{Cache 容量}}$。
显然,主存中的每一块映射到 Cache 中的位置是唯一的。
不命中:标记不相等或有效位为 0。
比较器数量:1 个(因为每个主存块只能映射到唯一的 Cache 行)。
优点:实现简单,对于任意一个地址,只需对比一个标记,速度最快;标记所占的额外空间开销最少。
缺点:不够灵活,Cache 存储空间利用不充分(即使 Cache 的其他地方空着也不能占用),块冲突概率最高,空间利用率最低,命中率最低。
🐼比较器:位数等于标记字段的位数,用于比较主存地址中的标记字段和 Cache 行标记字段。访存时根据标记字段的内容来访问 Cache 行中的主存块,因而其查找过程是一种 “按内容访问” 的存取方式,故比较器是一种 “相联存储器”。
全相联映射
主存中的每一块可以装入 Cache 中的任何位置,每行的标记用于指出该行取自主存的哪一块。
比较器数量:每个 Cache 行都设置一个比较器。
优点:比较灵活,Cache 块的冲突概率低(只要有空闲 Cache 行,就不会发生冲突);空间利用率高;命中率高。
缺点:标记的比较速度最慢,有可能需要对比所有行的标记;实现成本较高,需要设置较多的比较器(相联存储器价格昂贵)。时间开销和硬件开销都较大,不适合大容量 Cache。
组相联映射
N 路组相联映射:每 N 个 Cache 行为一组。实质是将 N 个 Cache 行合并,组内采用全相联方式,组间采用直接映射方式。
Cache 组号 = 主存块号 mod Cache 组数。
比较器数量:N 个。
评价:另外两种方式的折中,综合效果较好。路数越大,即每组的行数越大,发生块冲突的概率越低,但相联比较电路也越复杂。选定适当的数量,可使成本接近直接映射,同时性能上接近全相联映射。
一组只有一行 = 直接映射。
🎃三种映射方式的简单比较
- 直接映射的每个主存块只能映射到 Cache 中的某一固定行(1 个比较器)。
- 全相联映射的每个主存块能映射到所有 Cache 行(每行 1 个比较器)。
- N 路组相联映射的的每个主存块可以映射到 N 行(N 个比较器)。
当 Cache 大小、主存块大小一定时:
- 直接映射的命中率最低,全相联映射的命中率最高。
- 直接映射的判断开销最小、所需时间最短,全相联映射的判断开销最大、所需时间最长。
- 直接映射标记所占的额外空间开销最小,全相联映射标记所占的额外空间开销最大。
Cache 中主存块的替换算法
从主存向 Cache 传送一个新块,当 Cache 或 Cache 组中的空间已被占满时,就需要使用替换算法替换或淘汰 Cache 行。
☝😋采用全相联映射时,替换范围为所有 Cache 行;采用 N 路组相联映射时,替换范围为新块映射到的 Cache 组中的 N 个 Cache 行;采用直接映射时,无需考虑替换算法,因为一个给定的主存块只能放到唯一的固定 Cache 行中,所以无条件地把原先对应位置的主存块替换掉即可。
随机 RAND 算法
随机选一行替换。
优点:实现简单。
缺点:完全没考虑局部性原理,命中率低,实际效果很不稳定。
先进先出 FIFO 算法
选最早被调入的行替换。
优点:比较容易实现。
缺点:没有遵循局部性原理,效果差。
近期最少使用 LRU 算法
选近期内最久没有被访问的行替换。属于堆栈类算法。
基于局部性原理,近期被访问过的主存块在不久的将来也很有可能被再次访问,因此淘汰最久没被访问过的块是合理的。
实现:每行设置一个计数器,用于记录多久没被访问。行总数为 $2^n$ 时,计数器位数为 $n$(N 路组相联位数为 $\log_2\text{N}$)。
计数器的变化规则:
- 未命中且还有空闲行时,新装入的行的计数器置 0,其余非空闲行全加 1。
- 未命中且无空闲行时,计数值最大的行的信息块被淘汰,新装行的计数器置 0,其余全加 1。
- 命中时,所命中的行的计数器清零,值比其低的计数器加 1⚠,其余不变(值比其高的计数器加 1 也可以,但没必要,不加的话能使计数器位数不超过 $n$)。
LRU 算法实际运行效果优秀,Cache 命中率高。
若被频繁访问的主存块数量 > Cache 行的数量,则有可能发生 “抖动”,命中率变得很低。
最不经常使用 LFU 算法
将一段时间内被访问次数最少的行换出。
实现:每行设置一个计数器,用于记录被访问过多少次。新调入的块计数器为 0,之后每被访问一次计数器加 1。需要替换时,选择计数器最小的一行;若有多个计数器最小的行,可按行号递增或 FIFO 策略进行选择。
计数器的位数应该与时间段长度有关(猜的)。
并没有很好地遵循局部性原理,曾经被经常访问的主存块在未来不一定会用到,因此实际运行效果不如 LRU。
Cache 写策略
目标:既保证主存块和 Cache 块的数据一致性,又尽量提升效率。
全写法
全写法(write through)的基本做法是:当 CPU 执行写操作时,若写命中,则同时写 Cache 和主存;若写不命中,则有以下两种处理方式。
写分配法(write allocate)
先在主存块中更新相应存储单元,然后分配一个 Cache 行将更新后的主存块装入分配的 Cache 行中。
这种方式可以充分利用空间局部性,但每次写不命中都要从主存读一个块到 Cache 中,增加了读主存块的开销。
非写分配法(not write allocate)
仅更新主存单元而不把主存块装入 Cache 中。
这种方式可以减少读入主存块的时间,但没有很好利用空间局部性。
由此可见,全写法实际上采用的是对主存块信息及其所有副本信息全都直接同步更新的做法,因此通常被称为通写法或直写法,也有教材称之为写直达法。
为了减少写主存的开销,通常在 Cache 和主存之间加一个写缓冲(writebuffer)。
在 CPU 写 Cache 的同时,也将信息写入写缓冲,然后由存储控制器将写缓冲中的内容写入主存。写缓冲是一个 FIFO 队列(SRAM 实现),一般只有几项,在写操作频率不是很高的情况下,因为 CPU 只需要将信息写入快速的写缓冲而不需要写慢速的主存,因而效果较好。但是,如果写操作频繁发生,则会使写缓冲饱和而发生阻塞。
回写法
回写法(write back)的基本做法是:当 CPU 执行写操作时,若写命中,则信息只被写入 Cache 而不被写入主存;若写不命中,则在 Cache 中分配一行,将主存块调入该 Cache 行中并更新 Cache 中相应单元的内容。因此,该方式下在写不命中时,通常采用写分配法进行写操作。
在 CPU 执行写操作时,回写法不会更新主存单元,只有当 Cache 行中的主存块被替换时,才将该主存块内容一次性写回主存。这种方式的好处在于减少了写主存的次数,因而大大降低了主存带宽需求。为了减少写回主存块的开销,每个 Cache 行设置了一个修改位/脏位,若修改位为 1,则说明对应 Cache 行中的主存块被修改过,替换时需要写回主存;若修改位为 0,则说明对应主存块未被修改过,替换时不需要写回主存。
由此可见,该方式实际上采用的是回头再写或最后一次性写的做法,因此通常被称为回写法或一次性写方式,也有教材称之为写回法。
由于回写法没有同步更新 Cache 和主存内容,所以存在 Cache 和主存内容不一致而带来的潜在隐患。通常需要其他的同步机制来保证存储信息的一致性。
通常搭配:全写法 + 非写分配、回写法 + 写分配法。
分配是指 Cache 行的分配。回写法保证 Cache 的即时更新,所以它通常搭配写分配法。
注意写不命中时,写分配法在全写法和回写法中的操作是有区别的:搭配全写法时,是先在主存块中更新,再装入 Cache;而搭配回写法时,是装入 Cache 中后再进行更新。
只需记住,在写操作中,全写法总是能保证主存块和 Cache 信息同步;而回写法总是不能保证主存块和 Cache 信息同步,不管是写命中还是不命中。回写法只让 Cache 内容保持最新。
Cache 总容量的计算
Cache 的总容量包括:
存储容量
标记阵列/地址映射表容量
每个 Cache 行对应一个标记项/表项。标记项/表项的内容有:
有效位(1)、一致性维护位/脏位(1)(回写法)、替换算法控制位/计数器(LRU/LFU)、标记 Tag。
分离的 Cache 结构
随着指令流水技术的发展,需要将指令 Cache 和数据 Cache 分开涉及,这就有了分离的 Cache 结构,也称哈佛 Cache。
取指和取数分别到不同的 Cache 中寻找,使指令流水线中取指部分和取数部分很好地避免冲突,即减少了指令流水线的冲突。
允许 CPU 在同一个 Cache 存储周期内同时提取指令和数据,可以保证不同的指令同时访存。
分离的指令和数据 Cache 还可以充分利用指令和数据的不同局部性来优化性能。
指令 Cache 通常比数据 Cache 具有更好的空间局部性:因为指令流通常是顺序执行的,而数据流跳转或随机访问的概率较高。
多级 Cache
近年来,多级片内 Cache 系统已成为主流。目前 Cache 基本上都在 CPU 芯片内,且使用 L1 和 L2 Cache,甚至有 L3 Cache,CPU 的访问顺序为 L1 Cache、L2 Cache 和 L3 Cache。
由于多级 Cache 中各级 Cache 所处的位置不同,使得对它们的设计目标有所不同。离 CPU 越远,访问速度越慢(仍比主存快),容量越大(仍比主存小)。例如假定是两级 Cache。那么,对于 L1 Cache,通常更关注速度而不要求有很高的命中率,因为即使不命中,还可以到 L2 Cache 中访问,L2 Cache 的速度比主存速度快得多;而对于 L2 Cache,则要求尽量提高其命中率,因为若不命中,则必须到慢速的主存中访问,其缺失损失会很大而影响总体性能。
通常 L1 Cache 采用分离 Cache,即数据 Cache 和指令 Cache 分开设置,L2 Cache 和 L3 Cache 为联合 Cache。
各级 Cache 间常采用全写法,Cache 和主存间常采用回写法。下图是一个含有两级 Cache 的系统,L1 Cache 对 L2 Cache 使用全写法,L2 Cache 对主存使用回写法,由于 L2 Cache 的存在,其访问速度大于主存,因此避免了因频繁写时造成的写缓冲饱和溢出。
在多级 Cache 中,有全局缺失率和局部缺失率两种不同的概念。全局缺失率是指在所有级 Cache 中都缺失的访问次数占总访问次数的比率;局部缺失是指在某级 Cache 中缺失的访问次数占对该级 Cache 的总访问次数的比率。例如,对于两级 Cache,若 CPU 总的访存次数为 100,在 L1 Cache 命中的次数为 94,剩下的 6 次中,在 L2 Cache 命中的次数为 5,只有 1 次需要访问主存,则全局缺失率为 1%,L1 Cache 和 L2 Cache 的局部缺失率分别为 6% 和 16.7%。
Cache 读缺失处理
整个过程全部由硬件实现
读数据 Cache 缺失
对主存进行读操作(以 Cache 块为单位),将包含有所需数据的块写入 Cache 中,并更新有效位和标记位。
若 Cache 已满,则先对 Cache 行进行替换。
然后再从刚更新的 Cache 中取数据,而非主存。
取指令 Cache 缺失
程序计数器恢复当前指令的值。
跟数据 Cache 缺失一样的操作。
重新执行当前指令(从取指开始)。
虚拟存储器
主存和辅存共同构成了虚拟存储器,二者在硬件和系统软件的共同管理下工作。
虚拟存储器具有主存的速度和辅存的容量。
对于应用程序员而言,虚拟存储器是透明的。
虚拟存储器基本概念
地址空间
虚拟存储器将主存和辅存的地址空间统一编址,形成一个庞大的地址空间。在这个空间内,用户可以自由编程,而不必在乎实际的主存容量和程序在主存中实际的存放位置。
虚拟存储器的三个地址空间:
用户编程允许涉及的地址称为虚地址或逻辑地址,虚地址对应的存储空间称为虚拟空间或程序空间。
实际的主存单元称为实地址或物理地址,实地址对应的是主存地址空间,也称实地址空间。
虚地址比实地址要大得多。
虚拟存储器与主存和辅存的关系
虚拟存储机制采用全相联映射⚠,每个虚页面可以存放到对应主存区域的任何一个空闲页位置。
当进行写操作时,不能每次写操作都同时写回磁盘,因而在处理一致性问题时,采用回写法⚠。
页式虚拟存储器
页表
注意下图中物理页和磁盘地址两个字段是合并的,使用时根据有效位来区分。
快表 TLB
又称相联存储器 TLB,是具有并行查找能力的高速缓冲存储器,位于 CPU,属于 SRAM。
基于局部性原理,存放有若干页表项,以减少访问内存(慢表)的次数。
采用相联存储器件组成,按内容查找,查找速度快。
相联存储器的基本原理是把存储单元所存内容的某一部分作为检索项(即关键字项)去检索该存储器,并将存储器中与该检索项符合的存储单元进行读取或写入,所以它是按内容指定方式和地址指定方式相结合进行寻址的存储器。
和主存的映射方式通常采用全相联或组相联方式。
TLB 项内容 = TLB 标记字段 + 页表项内容。在全相联方式下,TLB 标记字段为虚页号;组相联方式下,虚页号高位部分为 TLB 标记字段,低位部分为 TLB 组索引。
具有 TLB 和 Cache 的多级存储系统
TLB 冗余了活跃的页表项(原本在内存的慢表中),用于虚拟地址转换为物理地址时;Cache 则是冗余了活跃的内存块,用于通过物理地址访问内存时。
TLB 和 Cache 的访问过程
TLB 缺失后需要将慢表中的相应表项更新到 TLB。若 TLB 已满,则还需要采用替换策略。
带 TLB 虚拟存储器的 CPU 访存过程
TLB、Cache、Page 缺失组合的分析
在一个具有 Cache 和 TLB 的虚拟存储系统中,CPU 一次访存操作可能涉及 TLB、页表(主存)、Cache、主存和磁盘的访问。
相应地,CPU 访存过程中存在三种缺失情况:
- TLB 缺失:要访问的页面的页表项不在 TLB 中。
- Cache 缺失:要访问的主存块不在 Cache 中。
- Page 缺失:要访问的页面不在主存中。
这三种缺失的可能组合情况为:
⚠注意:TLB 命中则 Page 必然命中,Page 缺失则 TLB、Cache 必然缺失。
缺失的处理:
- TLB 缺失处理:既可以用硬件又可以用软件来处理。
- Cache 缺失处理:由硬件完成。
- Page 缺失处理(缺页处理):由软件完成。操作系统通过缺页异常处理程序来实现。
段式虚拟存储器
段表比基本段式存储器多了个装入位。装入位用来指示该段是否已调入内存。
段页式虚拟存储器
把程序按逻辑结构分段,每段再划分为固定大小的页,主存空间也划分为大小相等的页,程序对主存的调入、调出仍以页为基本交换单位。
每个程序对应一个段表,每段对应一个页表,段的长度必须是页表的整数倍,段的起点必须是某一页的起点。
虚拟存储器 vs Cache
相同之处
- 最终目标都是为了提高系统性能,两者都有容量、速度、价格的梯度。
- 都把数据划分为小信息块,并作为基本的传递单位,虚存系统的信息块更大。
- 都有地址的映射、替换算法、更新策略等问题。
- 依据程序的局部性原理应用 “快速缓存” 的思想,将活跃的数据放在相对高速的部件中。
不同之处
Cache 主要解决系统速度;虚拟存储器为了解决主存容量。
Cache 全由硬件实现,是硬件存储器,对所有程序员透明;
虚拟存储器由 OS 和硬件共同实现,是逻辑上的存储器,对系统程序员不透明,但对应用程序员透明。
虚拟存储器系统不命中时对系统性能影响更大。
主存和硬盘速度差太多:CPU 速度约为 Cache 的 10 倍,主存的速度为硬盘的 100 倍以上。
CPU 与 Cache 和主存都建立了直接访问的通路,而辅存与 CPU 没有直接通路。
也就是说在 Cache 不命中时主存能和 CPU 直接通信,同时将数据调入 Cache;而虚拟存储器系统不命中时,只能先由硬盘调入主存,而不能直接和 CPU 通信。
刷题总结
注意区分存储器地址线数和芯片地址引脚数
RAM 和 ROM 都是随机访问。
CD-ROM 不属于 ROM,它是串行访问(直接存取)存储器。
多模块存储器主要是去解决访存速度的问题,而非是为了扩容。
Cache 容量计算,别忘了有效位。
代码题局部性的判断
时间局部性:一个内存位置被重复引用。
空间局部性:若一个内存位置被引用,则它附近的位置很快也会被引用。
Cache 的一次缺失损失时间为从主存传输一个内存块的时间⚠
若采用突发传送,则每个突发传送总线事务只需发送一次地址和一次读命令;
若存储器模块采用交叉方式组织,则可以采用流水线工作方式轮流启动模块进行传输。
王道 P127 选择 23、34。
Cache FIFO 替换算法无须对每个 Cache 行记录替换信息❌
需要对每个 Cache 行打一个时间戳,记录何时装入了一个新主存块。
写策略的选择:
1)处理器主要运行包含大量存储器写操作的数据访问密集型应用。
回写法。减少访存次数。
2)处理器运行程序的性质与 1)相同,但安全性要求高得多,不允许有任何数据不一致的情况发生。
全写法。保证数据的一致性。
写缓冲是用在全写法中的。
Cache LRU 替换算法替换控制位(计数器)位数
全相联映射:行总数为 $2^n$ 时,位数为 $n$。
组相联映射:N 路组相联,位数为 $\log_2\text{N}$。
Cache 缺失率计算好题:王道 P127 选择 30、王道 P128 应用 04。
逻辑地址用十进制给出,地址转换时直接做除法得到页号和页内偏移地址,没必要转换成二进制做(要转也是用除基取余法,别因为十六进制做多做昏头了)。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ZERO!