分页内存地址转换点滴

环境与条件:CPU 和操作系统都为 32 位,主存按字节编址

一、页大小的确定

一言以蔽之——在页表所占内存页内填充内存的耗费上做取舍、折中

以下极端情况的对比,用以阐明为什么要取舍、折中

A、页面大小 = 1Byte

  • 颗粒度到达极致细微、系统永远不必为页面填充不需要的内存
  • 但页表项目达到 2^32 个,占用了整个内存

B、页面大小 = 4GBytes

  • 每当新进程启动时,都需要将 4G 内存交换到磁盘
  • 页表中只有一个条目,因此几乎不占用任何内存

因此:

x86 设计人员发现 4K 大小的页面是很好的庸点

当然,随着 CPU 地址总线位数的扩张,系统中物理内存的膨胀,4K 也并不是总是合适的大小。

二、页大小 & 页内偏移量位数

已确定页大小,可算出页内偏移量需要多少位,如常见的页面尺寸 4K = 4096Bytes

$$ \log_{2}{4096} = 12,即:需要12_{bits} $$

已知页内偏移量占用 12 位,则可算出页大小

$$ 2^{12} = 4096_{Bytes} $$

页内偏移范围:

BIN HEX
000000000000 0x0000
000000000001 0x0001
... ...
111111111111 0x0FFF

三、页大小 & 页框大小 & 页表项数 & 物理内存块数

$$ \begin{array}{l} 物理内存块数 = \frac{物理内存(寻址范围)\equiv 2^{N}}{页大小},其中 N = 地址总线条数 \end{array} $$ $$ 有:页大小 \equiv 页框大小,且:页表项数 \equiv物理内存块数 $$

四、页表项大小及其存储内容

一个页表项的大小(即:占用二进制位数),至少要能容纳块号最大的物理内存块首地址的位数

例如:32 位地址总线

$$ \begin{array}{l} 寻址范围: 2 ^{32} = 4294967296_{Bytes} = 4G_{Bytes} \end{array} $$ $$ 页面大小(即:页框大小) = 4096_{Bytes} = 4K_{Bytes} $$ $$ 则,页框数 = \frac{4G}{4K} = \frac{2 ^{32}}{2^{12}} = 2^{32-12} = 2^{20} $$

物理内存块号范围:

BIN HEX
00000000000000000000 0x00000
00000000000000000001 0x00001
... ...
11111111111111111111 0xFFFFF

即:页表项中指向物理内存块号部分需要 20bits,而 2Bytes = 2 * 8bits = 16bits,不够;至少需要 3Bytes = 3 * 8bits = 24bits,就是说占 3 个字节浪费的 bit 最少。然而,需要额外考虑:

  • 页表项需要连续内存存储,但 3 不是 2 的整数次幂,按页面对其无法严密填满单个页面
  • 内存页除了地址,还有读写性质、运行级别等等属性需要占用 bit
  • 避免内存管理本身使用的内存过多

等等因素,所以一般页表项大小4Bytes32bits

高 20 位(31-12)给了块号,低 12 位(11-0)被用来存放内存页属性,详见下图 PTE(Page-Table Entry)部分

五、线性地址->物理地址转换过程

  1. 进程访问某个逻辑地址时,MMU 将逻辑地址分为页号 Pn 和页内地址 offset
  2. 页号大于页表长度,越界错误
  3. 页表项的地址 PTE = 页表起始地址 PTB + [页号 Pn * 表项大小 sizeof(PTE)],从而得到对应的物理块号 Pb
  4. 页和物理块的大小是一致的,所以:页内地址 = 块内地址
  5. 最终的物理地址 PA = 物理块号 Pb * 页大小 sizeof(Page) + 页内地址 offset

本文采用 知识共享署名许可协议(CC-BY 4.0)进行许可,转载注明来源即可。如有错误劳烦评论或邮件指出。


comments powered by Disqus