页表,分为单级页表和多级页表。
页表项中存的都是物理地址的偏移。
在页表机制下,每个虚拟地址由两部分组成:第一部分标识虚拟地址的虚拟页号,第二部分标识虚拟地址的页内偏移。在地址翻译过程中,MMU首先解析得到虚拟地址中的虚拟页号,并通过虚拟页号去该应用程序的页表中找到对应条目,然后取出条目中存储的物理页号,最后用该物理页号去对应的物理页起始地址加上虚拟地址的页内偏移,得到最终的物理地址。
在32位机器上,单级页表通常使用4字节的页表项(Page Table Entry, PTE)来表示每个虚拟页面对应的物理地址,因此单级页表占用的内存大小为:
总页数 × 每个页表项的大小
要计算总页数,可以先计算出虚拟地址空间的大小,然后将其除以页面大小。在32位机器上,一个进程的虚拟地址空间大小为4GB,因此总页数为:
4GB / 4KB = 2^20
也就是说,在32位机器上,单级页表需要管理2^20个页面。因此,单级页表占用的内存大小为:
2^20 × 4B = 4MB
也就是说,单级页表需要占用4MB的内存空间来存储所有的页表项。这个空间开销相对较大,特别是当系统中有很多进程时,会占用大量的内存资源。为了解决这个问题,现代操作系统通常采用多级页表来优化内存的使用。
2023/6/20 07:16:53
为什么页表占用的内存资源会随着进程数量增多呢?物理页表不是进程间复用的吗?
2023/6/20 07:17:07
在虚拟内存系统中,每个进程都有自己的页表来管理其虚拟地址空间和物理地址空间之间的映射关系。因此,当系统中有多个进程时,就需要为每个进程维护一个独立的页表。
虽然物理页表是可以在不同进程之间重用的,但每个进程都有自己的虚拟地址空间,因此每个进程的页表都是不同的。而且,每个页表项中通常需要存储一些与进程相关的信息,例如页面状态、访问权限等,这些信息是不能共享的。因此,随着进程数量的增多,页表占用的内存资源也会相应地增加。
当然,在一些特殊情况下,例如所有进程都具有相同的地址空间布局或使用了共享内存等机制,可以采用一些优化措施来减少页表占用的内存资源。
不过,一般虚拟地址空间要比物理地址空间大。最早32位机器的时候,很少有能达到4G内存空间的。当流行4G以上内存空间时,机器一般都是64位。
在64位架构的机器上,一个进程的虚拟地址空间大小理论上可以达到2的64次方字节,即16 EB(exabytes,十八亿GB)。这个空间远远超过了当前计算机系统所能提供的物理内存容量。实际上,大多数操作系统将进程的地址空间限制在相对较小的范围内,例如Linux x86_64将用户空间限制在128 TB。不过,即使如此,64位架构依然能够支持更高的内存容量和更高的性能。
综上,大多数情况下,都是虚拟地址空间要大于物理地址空间。
我们以比较简单的例子来演绎一下这个过程。32位机器,4G物理内存。
假设单个进程占满所有虚拟地址空间。
如果用单级页表来表示:页表需要占用物理内存4MB。
如果2级别页表(10+10+12)来表示:则需要16M的物理内存。
从上面的对比结论可以看出,多级页表并不省内存。那是因为我们上面是基于进程占满虚拟地址空间的前提来分析的。
假设单个进程只占用了前面的连续256M虚拟内存空间。我们再来对比下:
单级页表:页表需要占用的物理内存仍然是4MB。
2级页表:需要的页数是256M/4K = 65536个物理页,一个二级页表(占4K物理内存)能表示1024(1K)个物理页地址,因此65536个物理页面需要65536/1024 = 64 个二级页表,同理,一个一级页表,能够包含1K个二级页表首地址,所以一个一级页就够了(能涵盖64个二级页表)。综上,需要64 + 1 = 65个物理页来存储虚拟地址和物理地址的映射关系,也就是65 * 4K = 260K物理内存来存储两级页表信息。远远小于单级页表的4M内存。