操作系统中的多级页表到底是为了解决什么问题?

我正在看的教材上说多级页表是为了解决虚拟内存太大的问题。怎么解释?我想的是,因为把内存分为4K一页的话,虚拟内存太大,一页没法保存完整的页表。为什么一…
关注者
168
被浏览
241,783
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

页表在哪里?

一般来说,任何进程切换都会暗示着更换活动页表集。Linux内核为每一个进程维护一个task_struct结构体(即进程描述符PCB),task_struct->mm_struct结构体成员用来保存该进程的页表。在进程切换的过程中,内核把新的页表的地址写入CR3控制寄存器。CR3中含有页目录表的物理内存基地址,因此该寄存器也被称为页目录基地址寄存器PDBR(Page-Directory Base address Register)。

MMU是什么?

MMU是CPU的一部分,每个处理器core都有一个MMU,包含:

  • TLB:是页表的高速缓存,存储着最近转化的一些目录项
  • Table Walk Unit:负责从页表中读取虚拟地址对应的物理地址

虚拟地址怎么转化为物理地址?

对于每次转换,MMU首先在TLB中检查现有的缓存。如果没有命中,根据CR3寄存器,Table Walk Unit将从内存中的页表查询。


二级页表的内存占用

做个简单的数学计算,假设虚拟地址空间为32位(即4GB)。

每个页面映射4KB以及每条页表项占4B:

  • 一级页表:进程需要1M个页表项(4GB / 4KB = 1M, 2^20个页表项),即页表(每个进程都有一个页表)占用4MB(1M * 4B = 4MB)的内存空间。
  • 二级页表:一级页表映射4MB(2^22)、二级页表映射4KB,则需要1K个一级页表项(4GB / 4MB = 1K, 2^10个一级页表项)、每个一级页表项对应1K个二级页表项(4MB / 4KB = 1K),这样页表占用4.004MB(1K * 4B + 1K * 1K * 4B = 4.004MB)的内存空间。

多级页表的内存空间占用反而变大了。


多级页表为什么省内存?

二级页表可以不存在

我们反过来想,每个进程都有4GB的虚拟地址空间,而显然对于大多数程序来说,其使用到的空间远未达到4GB,何必去映射不可能用到的空间呢?

也就是说,一级页表覆盖了整个4GB虚拟地址空间,但如果某个一级页表的页表项没有被用到,也就不需要创建这个页表项对应的二级页表了,即可以在需要时才创建二级页表。做个简单的计算,假设只有20%的一级页表项被用到了,那么页表占用的内存空间就只有0.804MB(1K * 4B + 0.2 * 1K * 1K * 4B = 0.804MB),对比单级页表的4M是不是一个巨大的节约?

那么为什么不分级的页表就做不到这样节约内存呢?我们从页表的性质来看,保存在主存中的页表承担的职责是将虚拟地址翻译成物理地址;假如虚拟地址在页表中找不到对应的页表项,计算机系统就不能工作了。所以页表一定要覆盖全部虚拟地址空间,不分级的页表就需要有1M个页表项来映射,而二级页表则最少只需要1K个页表项(此时一级页表覆盖到了全部虚拟地址空间,二级页表在需要时创建)。


二级页表可以不在主存

其实这就像是把页表当成了页面。回顾一下请求分页存储管理,当需要用到某个页面时,将此页面从磁盘调入到内存;当内存中页面满了时,将内存中的页面调出到磁盘,这是利用到了程序运行的局部性原理。我们可以很自然发现,虚拟内存地址存在着局部性,那么负责映射虚拟内存地址的页表项当然也存在着局部性了!这样我们再来看二级页表,根据局部性原理,1024个第二级页表中,只会有很少的一部分在某一时刻正在使用,我们岂不是可以把二级页表都放在磁盘中,在需要时才调入到内存?我们考虑极端情况,只有一级页表在内存中,二级页表仅有一个在内存中,其余全在磁盘中(虽然这样效率非常低),则此时页表占用了8KB(1K * 4B + 1 * 1K * 4B = 8KB),对比上一步的0.804MB,占用空间又缩小了好多倍!


参考如下:

cnblogs.com/justin-y-li

polarxiong.com/archives

starlab.io/blog/deep-di