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