Skip to content

Chap.8 虚拟内存 (Virtual Memory)


8.1 硬件和控制结构 (Hardware and Control Structures)

虚拟内存的实现是硬件(如MMU)和操作系统软件共同配合的奇迹。

核心概念核对 (Concept Check)

  • 虚拟内存 (Virtual Memory): 一种存储分配方案,允许将辅助存储器(如磁盘)作为主存来寻址。虚拟大小受限于计算机的地址方案和磁盘空间,而非实际的物理内存。
  • 局部性原理 (Principle of Locality): 算法利用局部性原理,预测哪些驻留页面在不久的将来最不可能被访问,从而将它们换出。局部性分为空间局部性和时间局部性。
  • 页表项控制位 (Page Table Entry Bits):
    • 页框号 (Frame number): 标识主存中页面的顺序编号。
    • 存在位 (Present/Valid bit): 指示该页当前是否在主存中。
    • 修改位 (Modify/Dirty bit): 指示该页自装入主存后是否被修改过。如果没有修改过,置换时就不需要将其写回磁盘。

底层逻辑剖析 (The 'Why')

  • 为什么要用转换后备缓冲区 (TLB)? 每次虚拟地址转换都需要访问内存中的页表,导致访存时间翻倍。TLB 是一个专用的高速缓存,保存了最近使用的页表项。其目的是在绝大多数情况下,避免去磁盘或主存中检索页表项,极大提升地址转换速度。
  • 为什么要设计多级页表 (Multilevel Page Tables)? 对于巨大的虚拟地址空间(例如 32 位或 64 位),单级页表会占用极其庞大的连续物理内存。多级页表允许页表本身也被分页并存放在虚拟内存中,只将顶层目录(Root page table)常驻主存。
  • 反置页表 (Inverted Page Table) 的意义是什么? 传统页表大小与虚拟地址空间成正比,而反置页表的大小与物理内存成正比。它利用哈希表映射,每个物理页框只对应一个页表项。页表项通常包含:页号、进程标识符、控制位和用于解决哈希冲突的链指针。
  • 为什么要结合分页和分段 (Combined Paging and Segmentation)? 分页对程序员透明,消除了外部碎片;而分段对程序员可见,支持不断增长的数据结构、模块化、共享和保护。段页式结合方案中,进程拥有一个段表,而每个段拥有自己的页表。

8.2 操作系统软件 (Operating System Software)

操作系统需要制定一系列策略来管理虚拟内存,以最小化缺页中断(Page Fault)带来的巨大开销。

核心概念核对 (Concept Check)

操作系统的虚拟内存策略主要包含以下六个方面:

  1. 读取策略 (Fetch Policy): 决定何时将页面调入主存。
    • 请求分页 (Demand Paging): 只有当访问到该页某个位置而发生缺页时,才将其调入主存。
    • 预分页 (Prepaging): 除了引发缺页的页面,还会将预期可能用到的其他页面一并调入。
  2. 放置策略 (Placement Policy): 决定页面放在哪个物理框(主要在NUMA架构中重要)。
  3. 置换策略 (Replacement Policy): 决定淘汰哪个页面。常见算法包括 OPT, LRU, FIFO, Clock。
  4. 驻留集管理 (Resident Set Management): 决定分配给进程多少个页框,以及置换范围。
  5. 清除策略 (Cleaning Policy):
    • 请求清除 (Demand Cleaning): 只有当页面被选中替换时才写回磁盘。
    • 预清除 (Precleaning): 在页面框被需要之前,将修改过的页面成批写回磁盘。
  6. 负载控制 (Load Control): 决定系统多道程序度,防止抖动。

底层逻辑剖析 (The 'Why')

  • 为什么 Clock 算法比 LRU 更实用? 真正的 LRU (最近最久未使用) 算法需要为每次内存访问记录时间戳或维护链表,硬件开销极大。Clock (时钟) 策略通过“使用位 (Use bit)”来近似 LRU:当发生置换时,指针扫描环形缓冲区,跳过使用位为 1 的页(将其置 0),替换掉遇到第一个使用位为 0 的页。
  • 局部置换与全局置换 (Local vs. Global Replacement): 固定分配策略要求分配给进程的页框数固定,因此发生缺页时,只能替换该进程自己的页面(局部置换)。

常见易错点 (Common Pitfalls)

  • Belady 异常 (Belady's Anomaly): 学生常认为分配给进程的物理页框越多,缺页率一定越低。但在 FIFO 置换算法 中,增加页框数有时反而会导致更多的缺页传输,这就是著名的 Belady 异常。
  • 驻留集 (Resident Set) vs 工作集 (Working Set):
    • 驻留集 指的是一个进程当前实际存在于主存中的页面集合。
    • 工作集 指的是一个进程在最近一段时间内被引用过的页面集合。系统应当试图让驻留集包含工作集,以降低缺页率。
  • 抖动 (Thrashing): 这不是硬件故障!抖动是指在虚拟内存机制中,处理器将大部分时间耗费在换入换出页面上,而不是执行指令上的系统过载现象。通常因为多道程序度过高、进程分配的页框不足以覆盖其局部性引发。

8.3 - 8.6 具体操作系统的内存管理

不同的操作系统在实现虚拟内存时有各自的特色结构。

1. UNIX 和 Solaris 内存管理

UNIX SVR4 采用了四个关键数据结构来管理分页:

  • 页表项 (Page Table Entry): 包含页框号、年龄、修改位、访问位、存在位等。
  • 磁盘块描述符 (Disk Block Descriptor): 记录页面在交换设备(Swap device)上的逻辑设备号和块号。
  • 页框数据表项 (Page Frame Data Table Entry): 描述物理页框的状态和引用计数。
  • 交换使用表项 (Swap-Use Table Entry): 记录交换设备页面的使用计数。

2. Linux 内存管理

  • 四级页表结构: 为了保持平台独立性并支持大地址空间,Linux 将虚拟地址分为四个字段:页目录 (Page Directory) 索引、页中间目录 (Page Middle Directory) 索引、页表 (Page Table) 索引,以及偏移量。
  • 页大小: 基础单位通常是 4KB,但也支持大页(Hugepages,如 2MB),后者可以显著减少 TLB 访问次数从而提高性能。

3. Windows 内存管理

  • 32位默认虚拟地址映射: Windows 为正常的 32 位用户进程提供了 4GB 的虚拟地址空间,默认划分为四个区域:
    1. 0x00000000 - 0x0000FFFF (64KB): NULL 指针分配区,不可访问,用于捕获空指针错误。
    2. 0x00010000 - 0x7FFEFFFF (~2GB): 用户可用地址空间。
    3. 0x7FFF0000 - 0x7FFFFFFF (64KB): 保护页(Guard page),不可访问,用于检查指针越界。
    4. 0x80000000 - 0xFFFFFFFF (2GB): 操作系统内核专属区域,用户态不可访问。

总结 (Summary)

虚拟内存不仅让程序员摆脱了主存容量的物理限制,更通过分页、分段硬件与复杂的页面调度算法(置换策略、驻留集管理等),在**性能(时间和缺页率)空间(内存利用率)**之间实现了极其微妙的平衡。理解本章的核心在于牢记 “局部性原理 (Locality)” 以及如何用最少的开销(如 TLB、Clock 算法)去逼近完美的预测。

書體

本站所載,間有由 AI 所生成者。其辭義真偽,請君自審之。