分页内存地址转换点滴
环境与条件: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
- 避免内存管理本身使用的内存过多
等等因素,所以一般页表项大小
取 4Bytes
共 32bits
。
高 20 位(31-12)给了块号,低 12 位(11-0)被用来存放内存页属性,详见下图 PTE(Page-Table Entry)部分
五、线性地址->物理地址转换过程
- 进程访问某个逻辑地址时,MMU 将逻辑地址分为页号 Pn 和页内地址 offset
- 页号大于页表长度,越界错误
- 页表项的地址 PTE = 页表起始地址 PTB + [页号 Pn * 表项大小 sizeof(PTE)],从而得到对应的物理块号 Pb
- 页和物理块的大小是一致的,所以:页内地址 = 块内地址
- 最终的物理地址 PA = 物理块号 Pb * 页大小 sizeof(Page) + 页内地址 offset
本文采用 知识共享署名许可协议(CC-BY 4.0)进行许可,转载注明来源即可。如有错误劳烦评论或邮件指出。