加速分页的两个问题
基本概念:
虚拟存储器的基本思想是:程序、数据和堆栈的总大小可能超过可用的物理内存的大小。由操作系统把程序当前使用的那些部分保留在主存中,而把其他部分保存在磁盘上。例如,对于一个16MB的程序,通过仔细地选择在每个时刻将哪4MB内容保留在内存中,并在需要时在内存和磁盘间交换程序的片段,这样这个程序就可以在一个4MB的机器上运行。
由程序产生的地址被称为虚拟地址,它们构成了一个虚拟地址空间。在使用虚拟存储器的情况下,虚拟地址不是被直接送到内存总线上,而且是被送到内存管理单元(Memory Management Unt,MMU),MMU把虚拟地址映射为物理内存地址。
虚拟地址空间以页面为单位划分。在物理内存中对应的单位称为页框。页面和页框的大小总是一样的。
两个问题:
这样的页表,有两个很主要的问题
- 地址映射必须非常快
- 页表有可能非常大
解决方案:
问题一:基于这样一个原理——大多数程序总是对少量页面进行多次访问,用一种小型硬件设备TLB(translation lookaside buffer),将少量虚拟地址直接映射到物理地址,而不必再访问页表。TLB通常位于MMU中,当虚拟页号不在TLB中,就正常查询页表,接着从TLB中淘汰一个页表项,并用新找到的页表项代替它(类似路由表更新的过程)。
问题二:
多级页表:通常一个进程并不需要一整个虚拟地址空间大小的内存,比如,一个需要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,就构成了物理地址。
倒排页表:(64位机)与传统页表的区别是使用页框号而不是虚拟页号来索引页表项。在这种方法中,虚拟地址的页号部分使用一个简单的散列函数映射到散列表中。散列表包含一个指向倒排表的指针,而倒排表中含有页表项。通过这个结构,散列表和倒排表中各有一项对应于一个实存页。因此,不论有多少个进程、支持多少虚拟页,页表的大小都是固定的。