Bootstrap

一级、二级页表

参考:https://zhuanlan.zhihu.com/p/393005902

参考:Linux--内存管理浅谈_51CTO博客_linux 内存 管理

在操作系统中,页表(Page Table)用于实现虚拟内存到物理内存的地址映射。随着虚拟地址空间的增大,页表的大小也会相应增长,导致单级页表在某些情况下占用大量内存。采用二级页表(或多级页表)可以有效地减少页表本身所占用的内存空间。下面详细说明为什么二级页表比单级页表更加节省地址空间。

一级页表:需要一个连续且完整的页表来映射整个虚拟地址空间。因为每个虚拟页都需要一个页表项,所以操作系统必须在进程启动时预先分配整个页表,即使大部分页表项未被使用。

二级页表:采用分层结构,页目录只需包含指向实际使用的二级页表的指针。只有当某个虚拟页被访问时,相关的二级页表才会被分配和初始化。这种按需分配方式避免了为未使用的虚拟页分配页表项,从而节省了内存。

1. 单级页表的内存消耗问题

假设一个系统使用32位虚拟地址和4KB的页大小,那么:

  • 每个页面的偏移地址为12位(因为 2^12=4096 字节)。

  • 虚拟地址的其余部分(32-12=20位)用于页号。

单级页表需要为每一个可能的页号存储一个页表项(Page Table Entry, PTE)。因此,页表的大小为:

页表大小=2^20×PTE大小

假设每个PTE占4字节,则:

页表大小=2^20×4字节=4MB

对于每一个进程,操作系统都需要为其分配一个4MB的页表,即使进程实际使用的内存远小于4MB,这部分未使用的页表空间也会被浪费。

2. 二级页表的结构

二级页表将单级页表分成多个较小的页表页(Page Table Page)。具体来说,虚拟地址被分为多个部分,例如:

  • 目录索引(Directory Index):用于选择一级页表中的一个页目录项。

  • 页表索引(Page Table Index):用于选择二级页表中的具体页表项。

  • 页内偏移(Offset):用于页面内部的地址定位。

以32位地址空间为例,可以将地址分为:

  • 10位目录索引

  • 10位页表索引

  • 12位页内偏移

这样,一级页表(页目录)包含 2^10=1024 个页目录项,每个页目录项指向一个二级页表。每个二级页表同样包含1024个页表项。

3. 节省地址空间的原因

采用二级页表后,只有那些被实际使用的二级页表才会被分配内存。假设一个进程只使用虚拟地址空间的部分区域,可能只需要部分的二级页表,而不需要整个单级页表。

举例说明

假设一个进程只使用4MB的虚拟内存:

  • 4MB / 4KB = 1024个页。

  • 需要的二级页表数目 = 1(因为一个二级页表可以管理1024个页)。

  • 页目录需要的空间 = 1024个页目录项,每个4字节,共4KB。

总共需要的页表空间为:

页目录+一个二级页表=4KB+4KB=8KB

而使用单级页表则需要4MB,显著减少了内存开销。

4. 进一步优化

多级页表(如二级页表)不仅限于两级,还可以扩展为三级、四级等,以适应更大的地址空间,同时进一步优化页表的内存使用。例如,现代的x86-64架构使用四级页表,以支持更大的虚拟地址空间。

5. 总结

二级页表通过分层管理页表,将页表的内存分配与实际使用的虚拟地址空间相对应,避免了单级页表中大量未使用的页表项所造成的内存浪费。这种分层结构使得页表更加高效地利用地址空间,特别是在虚拟地址空间较大且实际使用较为稀疏的情况下,二级页表能够显著减少操作系统的内存开销

;