使用虚拟内存的关键步骤是把应用程序使用的虚拟地址转换为处理器使用的物理地址,以便从内存中提取数据。这一步通过处理器上称为TLB(Translation Look-aside Buffer,转换旁视缓冲器)的部分实现。通常,一个TLB用于转换指令地址(指令TLB,或称ITLB),另一个TLB则用于转换数据地址(数据TLB,或称DTLB)。 每个TLB都是一个列表,包含每个内存页面的虚拟地址范围以及对应的物理地址范围。因此,当需要将虚拟地址转换为物理地址时,处理器首先将虚拟地址划分为虚拟页面地址(高位)和相对于页面起始地址的页内偏移量(低位),然后在TLB保存的转换列表中查找此虚拟页面的地址,获得该页面对应的物理地址,最后把物理地址与页内偏移量相加获得数据在物理内存中的地址,并根据此地址来提取数据。图1-17显示了这一过程。 遗憾的是,一个TLB能容纳的转换集极为有限,所以有时处理器要找的物理地址转换并未驻留在TLB中。在这种情况下,必须从称为页表的内存数据结构中提取地址转换,这种结构可以容纳更多从虚拟地址到物理地址的映射。当地址转换未驻留在TLB中时,这称为TLB未命中。TLB未命中会影响性能,对性能影响的大小则取决于从页表提取TLB条目是由硬件来完成还是由软件来管理。最新处理器对此做硬件处理。此外,也可能会产生页表未命中,不过大多数应用程序极少遇到这一事件。页表由软件管理,因此页表未命中事件通常开销极大、处理缓慢。 TLB与缓存有许多共同特征,也因此会遇到不少相同的问题。TLB会遭遇容量失效(capacity miss)和冲突失效(conflict miss)。容量失效是指应用程序映射的内存量大于TLB能映射的内存量。而在冲突失效的情况下,内存中多个页面映射到同一TLB条目,此时添加新映射会导致旧映射从TLB中退出。TLB的未命中率可与缓存使用相同的技术来降低。然而,对于TLB来说,有个可进一步加以改变的特征,即映射页的大小。 SPARC架构的默认页面大小为8 KB,x86的为4 KB,因此每个TLB条目都为一个8 KB或4 KB的页面提供物理或虚拟内存映射。现代的处理器可以处理多种页面尺寸,所以单个TLB条目能为大小为64 KB、256 KB、数兆字节乃至数千兆字节的页面提供映射。页面尺寸较大最明显的好处是映射应用程序使用的虚拟地址空间所需的TLB条目有所减少。使用较少的TLB条目意味着在载入新条目时,原TLB条目被淘汰的几率减小,从而得到较低的TLB未命中率。例如,以4 MB大小的页面映射1 GB大小的地址空间需要256个条目,而以8 KB大小的页面映射同样大小的内存则需要131 072个条目。256个条目也许能放入一个TLB,但131 072个条目却无法放入一个TLB中。 使用较大的页面尺寸缺点如下。 大页面的分配需要连续的物理内存块才能实现,没有足够大的连续内存就无法分配大页面。对于操作系统而言,如何处理和提供大页面是个难题。如果无法向应用程序提供一个大页面,则操作系统可选择移动周围的其他已分配物理内存或向应用程序提供多个较小的页面。 使用大页面的应用程序即使不需要也会保留相应大小的物理内存。这可能导致内存的使用效率低下,即使是小应用程序最终可能也会保留大量物理内存。 有一个多处理器系统特有的问题,即内存中的页面往往相对于其中一个处理器的访问延迟比另一个更低。页面尺寸越大,不同处理器上运行的线程共享该页面的可能性就越大。运行在具有较高内存延迟的处理器上的线程会运行较慢。这个问题将在1.3节中详细讨论。 对于大多数应用程序,使用较大的页面会改进性能,但在某些情况下,其他因素比使用大页面带来的好处更重要。