多级页表的原理

我之前一直有一个疑惑,为什么同样都是把页表存储在内存中,多级页表就比一级页表要省空间?

如果你也有这个疑惑,看完这篇博客你就明白了


先说一些基本概念(参考《现代操作系统》)


虚拟存储器的基本思想是:程序、数据和堆栈的总大小可能超过可用的物理内存的大小。由操作系统把程序当前使用的那些部分保留在主存中,而把其他部分保存在磁盘上。例如,对于一个16MB的程序,通过仔细地选择在每个时刻将哪4MB内容保留在内存中,并在需要时在内存和磁盘间交换程序的片段,这样这个程序就可以在一个4MB的机器上运行。


由程序产生的地址被称为虚拟地址,它们构成了一个虚拟地址空间。在使用虚拟存储器的情况下,虚拟地址不是被直接送到内存总线上,而且是被送到内存管理单元(Memory  Management Unt,MMU),MMU把虚拟地址映射为物理内存地址。


虚拟地址空间以页面为单位划分。在物理内存中对应的单位称为页帧。页面和页帧的大小总是一样的。


假设页面的大小为4KB,下面是一个页表给出虚拟地址与物理内存地址之间的映射关系


在上图为例的16个4KB页面情况下MMU的内部操作如下图


这样的页表,有两个很主要的问题

1)页表有可能非常大

2)地址映射必须非常快

这里重点讨论第一个问题,第二个问题可以通过硬件去解决。

第一个问题的产生是由于现代计算机使用的虚拟地址至少是32位的。比如,当页面大小为4KB时,32位的地址空间将有100万个页面,64位的地址空间则更多。虚拟地址空间中的100万个页面需要有100万个表项的页表。并且请记住,每个进程都需要有自己的页表(因为每个进程有自己的虚拟地址空间)。


显然不可能每个进程都将自己的页表保存在内存中。


避免把全部页表一直保存在内存中是多级页表的关键所在。特别是那些不需要的页表就不应该保留。


什么意思呢?对于一个进程而言,它的虚拟地址空间是相对于地址线而言的。假如有一台可以生成32位地址的计算机,地址范围就从0到4GB,且这些地址是虚拟地址。假设一个页面大小为4KB,那么就有100万个页面。假设存储一个页面需要1个byte去存储,那么一个进程就需要占用内存100万个byte,也就是1MB。每个进程都占用内存1MB去存储页表是件很浪费的事情,特别是当运行的总进程数多的时候,而且,这只是在32位地址的计算机的情况下,如果是在64位地址的计算机的情况下,如果按照相同的计算方法,一个进程的页表占用的空间一个普通内存根本放不下。关键是,一个进程,真的会需要一整个虚拟地址空间去存放吗?.


绝大多数都不需要,比如,一个需要12MB的进程,底端是4MB程序正文,后面是4MB数据,顶端是4MB堆栈,在数据顶端上方和堆栈之间是大量根本没有使用的空闲区。


通过一个顶级页表为真正有用的页表提供索引,这是我所理解的二级页表的本质。多级页表的原理类似。


上述的12MB的进程的二级页表如下图


虽然在图中的地址空间超过100万个页(1024个二级页表,每个二级页表有1024个页),实际上只需要四个页表:顶级页表以及0~4M、4M~8M和顶端4M的二级页表。顶级页表中1021(1024-3)个表项的“在/不在”位都被设为0,当访问它们时强制产生一个页面失效。


图中的顶级页表项的PT1有10位,代表顶级页表有2^10=1024个页表项(但大多的“在/不在”位都被设为0,因为没有用到),PT2有10位,代表二级页表有2^10=1024个页表项,一个页表项对应一个页面,也就是该页表项存储了虚拟地址的页帧号,用该页帧号加上Offset,就构成了物理地址。


举个例子,考虑32位虚拟地址0x00403004(十进制4206596),它位于数据部分12292字节处。它的虚拟地址对应PT1=1,PT2=2,Offset=4。MMU首先用PT1作为索引访问顶级页表得到表项1,它的地址范围是在它的4M块内的12288~16383(即绝对地址4206592~4210687)。这个表项含有虚拟地址0x00403004所在页面的页帧号。如果该页面不再内存中,页表表项中的“在/不在”位将是0,引发一次页面失效。如果该页面在内存中,从二级页表中得到的页帧号将与偏移量,也就是4结合构成物理地址。该地址被放到总线上并送到内存中。

猜你喜欢

转载自blog.csdn.net/fordreamyue/article/details/78887035