虚拟内存(Virtual Memory)

虚拟内存是将连接到 CPU 的物理内存与在其上执行的所有进程共享的机制。虚拟内存提供了一种保护机制,防止其他进程访问分配给某个进程的内存。虚拟内存还提供了重定位(relocation),即在不改变程序中地址的情况下,将程序加载到物理内存中任意位置的能力。

在支持虚拟内存的 CPU 中,程序使用虚拟地址进行访问。但当用户代码在虚拟地址上操作时,从内存中检索数据需要物理地址。此外,为了有效管理稀缺的物理内存,它被分为(pages)。因此,应用程序在操作系统提供的一组页上运行。

4KB 页的虚拟到物理地址转换。

4KB 页的虚拟到物理地址转换。

访问数据和代码(指令)都需要虚拟到物理地址转换。页面大小为 4KB 的系统的转换机制如图 VirtualMem 所示。虚拟地址被分为两部分。虚拟页号(最高有效的 52 位)用于索引页表,以产生虚拟页号和相应物理页之间的映射。最低有效的 12 位用于在 4KB 页内的偏移。这些位不需要转换,直接用于访问物理内存位置。

2 级页表示例。

2 级页表示例。

页表可以是单级的,也可以是嵌套的。图 L2PageTables 展示了一个 2 级页表的例子。注意地址如何被分成更多部分。首先要提到的是,最高有效的 16 位未被使用。这看起来像是浪费位,但即使有剩余的 48 位,我们也可以寻址 256 TB 的总内存(2^48^)。一些应用程序使用这些未使用的位来保存元数据,也称为指针标记(pointer tagging)。

嵌套页表是一棵基数树(radix tree),保存物理页地址和一些元数据。要在 2 级页表中找到转换,我们首先使用位 32..47 作为 1 级页表(也称为页表目录(page table directory))的索引。目录中的每个描述符指向 2^16^ 个 2 级表块之一。找到适当的 L2 块后,我们使用位 12..31 查找物理页地址。将其与页偏移(位 0..11)连接即得到物理地址,可用于从 DRAM 中检索数据。

页表的确切格式由 CPU 规定,原因我们稍后几段会讨论。因此,页表组织的变体受限于 CPU 所支持的内容。现代 CPU 支持具有 48 位指针(256 TB 总内存)的 4 级页表和具有 57 位指针(128 PB 总内存)的 5 级页表。

将页表拆分为多个级别不会改变总的可寻址内存。然而,嵌套方法不需要将整个页表存储为连续数组,也不分配没有描述符的块。这节省了内存空间,但在遍历页表时增加了开销。

未能提供物理地址映射称为页面错误(page fault)。如果请求的页面无效或当前不在主存中,就会发生这种情况。两个最常见的原因是:1)操作系统承诺分配一个页面但尚未用物理页面支持它;2)访问的页面被换出到磁盘,当前未存储在 RAM 中。

转换后备缓冲区(TLB,Translation Lookaside Buffer)

在分层页表中搜索可能代价高昂,需要遍历层次结构,可能进行多次间接访问。这种遍历称为页面遍历(page walk)。为了减少地址转换时间,CPU 支持一种称为转换后备缓冲区(TLB)的硬件结构,以缓存最近使用的转换。与常规缓存类似,TLB 通常设计为 L1 ITLB(指令)和 L1 DTLB(数据)的层次结构,后跟共享(指令和数据)L2 STLB。

为了降低内存访问延迟,L1 缓存查找可以与 DTLB 查找部分重叠,这得益于缓存相联度和大小的约束,允许在不使用物理地址的情况下进行 L1 组选择。1 然而,更高级别的缓存(L2 和 L3)——它们通常也是物理索引物理标记(PIPT)的,但无法从此优化中受益——因此在缓存查找之前需要地址转换。

TLB 层次结构保存相对较大内存空间的转换。尽管如此,TLB 中的未命中可能代价非常高昂。为了加速 TLB 未命中的处理,CPU 有一种称为硬件页面遍历器(hardware page walker)的机制。这种单元可以直接在硬件中执行页面遍历,通过发出所需的指令来遍历页表,而无需中断内核。这就是为什么页表的格式由 CPU 规定,操作系统必须遵守。高端处理器有多个硬件页面遍历器,可以同时处理多个 TLB 未命中。然而,即使有现代 CPU 提供的所有加速,TLB 未命中仍然会给许多应用程序带来性能瓶颈。

大页(Huge Pages)

较小的页面大小使得更有效地管理可用内存和减少碎片化成为可能。但缺点是需要更多页表条目来覆盖相同的内存区域。考虑两种页面大小:4KB(x86 上的默认值)和 2MB 的大页(huge page)大小。对于一个在 10MB 数据上操作的应用程序,在第一种情况下需要 2560 个条目,但如果将地址空间映射到大页上,只需要 5 个条目。这些在 Linux 上被称为大页(Huge Pages),在 FreeBSD 上称为超级页(Super Pages),在 Windows 上称为大页(Large Pages),但它们的含义相同。在本书的其余部分,我们将其称为大页。

图 HugePageVirtualAddress 展示了指向大页内数据的地址示例。就像默认页面大小一样,使用大页时确切的地址格式由硬件决定,但幸运的是,作为程序员我们通常不必担心这个问题。

指向 2MB 页面内的虚拟地址。

指向 2MB 页面内的虚拟地址。

使用大页大大减少了对 TLB 层次结构的压力,因为所需的 TLB 条目更少。它大大增加了 TLB 命中的机会。我们将在 [secDTLB] 和 [FeTLB] 中讨论如何使用大页来减少 TLB 未命中的频率。使用大页的缺点是内存碎片化,在某些情况下,由于操作系统更难管理大块内存并确保有效利用可用内存,页面分配延迟可能不确定。为了在运行时满足 2MB 大页分配请求,OS 需要找到一块连续的 2MB 内存。如果找不到,OS 需要重新组织页面,导致更长的分配延迟。

1. PIPT L1 缓存同时也是 VIPT 的最小相联度,无需将索引转换为物理地址就可以访问一个组 - https://stackoverflow.com/a/59288185

results matching ""

    No results matching ""