Skip to content

1. 深入理解 Linux 物理内存管理

小林coding

1.1 什么是物理内存地址

我们平时所称的内存也叫随机访问存储器( random-access memory )也叫 RAM 。而 RAM 分为两类:

  • 静态 RAM( SRAM ),这类 SRAM 用于 CPU 高速缓存 L1Cache,L2Cache,L3Cache。其特点是访问速度快,访问速度为 1 - 30 个时钟周期,但是容量小,造价高。
  • 动态 RAM ( DRAM ),这类 DRAM 用于我们常说的主存上,其特点的是访问速度慢(相对高速缓存),访问速度为 50 - 200 个时钟周期,但是容量大,造价便宜些(相对高速缓存)。

内存由一个一个的存储器模块(memory module)组成,它们插在主板的扩展槽上。常见的存储器模块通常以 64 位为单位( 8 个字节)传输数据到存储控制器上或者从存储控制器传出数据。

DRAM 芯片包装在存储器模块中,每个存储器模块中包含 8 个 DRAM 芯片,依次编号为 0 - 7 。

而每一个 DRAM 芯片的存储结构是一个二维矩阵,二维矩阵中存储的元素我们称为超单元(supercell),每个 supercell 大小为一个字节(8 bit)。每个 supercell 都由一个坐标地址(i,j)

  • i 表示二维矩阵中的行地址,在计算机中行地址称为 RAS (row access strobe,行访问选通脉冲)
  • j 表示二维矩阵中的列地址,在计算机中列地址称为 CAS (column access strobe,列访问选通脉冲)

图中 DRAM 芯片包含了两个地址引脚( addr ),因为我们要通过 RAS,CAS 来定位要获取的 supercell 。还有 8 个数据引脚(data),因为 DRAM 芯片的 IO 单位为一个字节(8 bit),所以需要 8 个 data 引脚从 DRAM 芯片传入传出数据。

注意这里只是为了解释地址引脚和数据引脚的概念,实际硬件中的引脚数量是不一定的。

1.1.1 DRAM 芯片的访问

  1. 首先存储控制器将行地址 RAS = 2 通过地址引脚发送给 DRAM 芯片。
  2. DRAM 芯片根据 RAS = 2 将二维矩阵中的第二行的全部内容拷贝到内部行缓冲区中。
  3. 接下来存储控制器会通过地址引脚发送 CAS = 2 到 DRAM 芯片中。
  4. DRAM芯片从内部行缓冲区中根据 CAS = 2 拷贝出第二列的 supercell 并通过数据引脚发送给存储控制器。

1.1.2 CPU 如何读写主存

CPU 与内存之间的数据交互是通过总线(bus)完成的,而数据在总线上的传送是通过一系列的步骤完成的,这些步骤称为总线事务(bus transaction)

其中数据从内存传送到 CPU 称之为读事务(read transaction),数据从 CPU 传送到内存称之为写事务(write transaction)

总线上传输的信号包括:地址信号,数据信号,控制信号。其中控制总线上传输的控制信号可以同步事务,并能够标识出当前正在被执行的事务信息:

  • 当前这个事务是到内存的?还是到磁盘的?或者是到其他 IO 设备的?
  • 这个事务是读还是写?
  • 总线上传输的地址信号(物理内存地址),还是数据信号(数据)?

如上图所示,其中系统总线是连接 CPU 与 IO bridge 的,存储总线是来连接 IO bridge 和主存的。

IO bridge 负责系统总线上的电子信号和存储总线上的电子信号的互相转换。IO bridge 也会将系统总线和存储总线连接到IO总线(磁盘等IO设备)上。

Warning

CPU 只会访问虚拟内存,在操作总线之前,需要把虚拟内存地址转换为物理内存地址,总线上传输的都是物理内存地址

1.1.2.1 CPU 读内存

首先 CPU 芯片中的总线接口会在总线上发起读事务(read transaction)。 该读事务分为以下步骤进行:

  1. CPU 将物理内存地址 A 放到系统总线上。随后 IO bridge 将信号传递到存储总线上。
  2. 主存感受到存储总线上的地址信号并通过存储控制器将存储总线上的物理内存地址 A 读取出来。
  3. 存储控制器通过物理内存地址 A 定位到具体的存储器模块,从 DRAM 芯片中取出物理内存地址 A 对应的数据 X。
  4. 存储控制器将读取到的数据 X 放到存储总线上,随后 IO bridge 将存储总线上的数据信号转换为系统总线上的数据信号,然后继续沿着系统总线传递。
  5. CPU 芯片感受到系统总线上的数据信号,将数据从系统总线上读取出来并拷贝到寄存器中。

1.1.2.2 如何从主存中读取数据

当主存中的存储控制器感受到了存储总线上的地址信号时,会将内存地址从存储总线上读取出来。随后会通过内存地址定位到具体的存储器模块。

存储控制器会将物理内存地址转换为 DRAM 芯片中 supercell 在二维矩阵中的坐标地址(RAS,CAS)。并将这个坐标地址发送给对应的存储器模块。随后存储器模块会将 RAS 和 CAS 广播到存储器模块中的所有 DRAM 芯片。依次通过 (RAS,CAS) 从 DRAM0 到 DRAM7 读取到相应的 supercell 。

一个 supercell 存储了一个字节( 8 bit ) 数据,这里我们从 DRAM0 到 DRAM7 依次读取到了 8 个 supercell 也就是 8 个字节,然后将这 8 个字节返回给存储控制器,由存储控制器将数据放到存储总线上。

CPU 总是以 word size 为单位从内存中读取数据,在 64 位处理器中的 word size 为 8 个字节。64 位的内存每次只能吞吐 8 个字节。

Note

CPU 每次会向内存读写一个 cache line 大小的数据( 64 个字节),但是内存一次只能吞吐 8 个字节。

在物理内存地址对应的存储器模块中,DRAM0 芯片存储第一个低位字节( supercell ),DRAM1 芯片存储第二个字节,......依次类推 DRAM7 芯片存储最后一个高位字节。

由于存储器模块中这种由 8 个 DRAM 芯片组成的物理存储结构的限制,内存读取数据只能是按照物理内存地址,8 个字节 8 个字节地顺序读取数据。所以说内存一次读取和写入的单位是 8 个字节。

所以在连续的物理内存地址实际上在物理上是不连续的。因为这连续的 8 个字节其实是存储于不同的 DRAM 芯片上的。每个 DRAM 芯片存储一个字节(supercell)。

1.1.2.3 CPU 写内存

CPU 芯片中的总线接口会向总线发起写事务(write transaction)。写事务步骤如下:

  1. CPU 将要写入的物理内存地址 A 放入系统总线上。
  2. 通过 IO bridge 的信号转换,将物理内存地址 A 传递到存储总线上。
  3. 存储控制器感受到存储总线上的地址信号,将物理内存地址 A 从存储总线上读取出来,并等待数据的到达。
  4. CPU 将寄存器中的数据拷贝到系统总线上,通过 IO bridge 的信号转换,将数据传递到存储总线上。
  5. 存储控制器感受到存储总线上的数据信号,将数据从存储总线上读取出来。
  6. 存储控制器通过内存地址 A 定位到具体的存储器模块,最后将数据写入存储器模块中的 8 个 DRAM 芯片中。

1.2 TODO