《操作系统导论》第23章:VAX/VMS 虚拟内存系统 - 深度知识架构
1. 核心矛盾 (The Crucial Problem)
如何避免“通用性魔咒 (Curse of Generality)”,构建一个既能掩盖底层硬件架构缺陷(如页太小、缺乏引用位),又能在性能差异巨大的全系列机器上高效运行的通用虚拟内存管理系统?
2. 核心概念 (Core Concepts)
- 驻留集大小 (Resident Set Size, RSS):
- 定义:操作系统规定一个进程可以保存在物理内存中的最大页数。
- 角色:内存公平分配的“边界控制阀”。它防止了某个“自私贪婪”的程序(Memory Hog)占用系统的所有物理内存,保证了多进程环境下的公平性。
- 分段的 FIFO (Segmented FIFO):
- 定义:一种结合了先入先出 (First-In-Out, FIFO) 队列和全局二次机会列表的页面替换策略。
- 角色:硬件缺陷的“软件补丁”。在 VAX 硬件页表项缺乏引用位的情况下,通过这种混合策略,用纯软件的方式极为巧妙地近似实现了最近最少使用 (Least-Recently-Used, LRU) 的效果。
- 按需置零 (Demand Zeroing):
- 定义:一种惰性分配形式,操作系统仅在页表项中做标记,只有当进程真正访问(读写)该页产生陷入时,操作系统才实际去寻找物理页、将其置零并映射。
- 角色:内存分配的“拖延症大师”。它消除了将未使用的页进行初始化的巨大无用开销。
- 写时复制 (Copy-On-Write, COW):
- 定义:当需要复制地址空间(如
fork())时,操作系统不实际拷贝数据,而是将原页和新页都映射到同一物理页并标记为只读。只有当其中一个进程尝试写入时,才触发异常并真正拷贝物理页。 - 角色:进程创建的“极致性能加速器”。极大地优化了内存复制的开销,是现代操作系统(特别是 UNIX)快速创建进程的基础。
- 定义:当需要复制地址空间(如
3. 逻辑演进 (Logical Evolution)
在构建 VMS 虚拟内存系统时,设计者(如 Dave Cutler)遇到了一系列硬件留下的“坑”,并用软件逐一化解:
- 挑战 1(硬件页太小导致页表过大):VAX 硬件的页大小仅为 512 字节。这意味着一个 32 位地址空间需要极为庞大的页表,甚至页表本身都难以放入物理内存。
- 成熟方案:VMS 通过将 32 位地址空间逻辑切分为用户空间(P0、P1)和系统空间(S)来减小页表。栈和堆之间的空白区域不需要页表项。并且,系统空间 S 的页表被映射到每个用户进程中,不仅节省了大量内存,还让内核与用户程序的数据交换变得极其简单。
- 挑战 2(硬件不支持引用位,无法实现 LRU):VAX 的页表项 (Page Table Entry, PTE) 中没有引用位(Reference Bit),操作系统根本不知道哪些页最近被使用过。
- 成熟方案:引入分段的 FIFO 策略。每个进程有一个基于 FIFO 的局部驻留集。当局部 FIFO 满了,最旧的页不会立刻被丢弃到磁盘,而是进入全局的干净页列表或脏页列表(二次机会列表)。如果进程在此期间再次访问该页,它就会被从全局列表中“拯救”回局部 FIFO;否则最终被踢出。这在没有硬件引用位的情况下实现了很好的命中率。
- 挑战 3(初级实现的无效性能损耗):如果在申请内存或
fork()时立刻分配物理页、置零或全部拷贝,哪怕这些页最终未被使用,也会浪费巨量的 CPU 时间和内存总线带宽。- 成熟方案:利用页表项中“保留给操作系统使用的位(OS-reserved fields)”,引入了按需置零和写时复制 (COW) 的纯软件惰性机制。将工作推迟到真正发生读写陷阱的那一刻,从而完全避免了不必要的初始化和拷贝。
4. 机制与策略 (Mechanisms vs. Policies)
在 VMS 中,软硬件的机制与策略被发挥到了极致:
- 底层的“实现手段”(机制 - Mechanisms):
- PTE 中的保留位 (Reserved OS Fields):虽然硬件只认识有效位、保护位和脏位,但硬件在 PTE 中预留了 5 位给操作系统。VMS 利用这些位记录页面的特殊软件状态(如这是一个“按需置零页”还是“COW页”),作为机制传达给陷入处理程序。
- 保护级别异常:硬件提供多种特权访问级别的保护机制。若试图写入只读页(如 COW 时),硬件触发机制抛出陷入异常给操作系统处理。
- 上层的“决策逻辑”(策略 - Policies):
- 全局与局部结合的替换策略:分段 FIFO 策略决定了当内存不足时,优先从局部驻留集 (RSS) 中以 FIFO 的顺序踢出页,并决定这些页在全局二次机会列表中的流转顺序。
- 聚集写入 (Clustering):VMS 在将脏页踢出到磁盘时采用了聚集策略,将多个相邻的页打包成一次大的 I/O 操作写入交换空间,从而极大提升了磁盘性能。
5. 设计折衷 (Design Trade-offs)
- 牺牲“初始的确定性执行时间”,换取“极致的内存与性能节约”:按需置零和写时复制 (COW) 都是惰性(Lazy)优化的典型代表。系统牺牲了程序在第一次访问内存时的性能(因为会产生引发陷阱的额外开销),换取了跳过那些“从未被使用的内存”的初始化和拷贝的巨大宏观性能提升。
- 牺牲“软件系统的极简性”,换取“弥补硬件缺陷的能力”:没有硬件引用位,原本操作系统的替换策略可以非常简单。但为了获得接近 LRU 的良好表现,VMS 忍受了极高的软件复杂度,设计了局部的 RSS FIFO 加双全局列表(干净/脏列表)的分段 FIFO 架构。
6. 关键洞察 (Key Insights)
- 将缺陷转化为美德 (Turn Flaws into Virtues):硬件没有提供引用位,看似是一个致命的缺陷,但 VMS 的工程师通过巧妙的软件设计(分段 FIFO 和二次机会缓存)绕过了它,甚至在某些情况下展现出了比简单硬件 LRU 更好的适应性。优秀的软件工程能够隐藏底层硬件的糟糕决策。
- 惰性是操作系统的美德 (Laziness is a Virtue in OS):在系统设计中,“能拖就拖”不仅不是坏事,反而是性能优化的核心法则。无论是延迟写回、按需置零,还是写时复制,推迟工作往往意味着这项工作最终可能根本不需要去做(例如进程还没写入 COW 内存就直接
exec()被覆盖了)。 - 保护与隔离也是为了共享 (Isolation enables Sharing):VMS 将操作系统的内核代码和数据直接映射到每个用户进程的 S 空间中,这大大降低了内核与用户空间传递数据的难度。而这种“同一地址空间内的共存”之所以可行,完全仰仗于硬件提供的多级页表保护位(User 模式无法访问 Kernel 级别的内存)。隔离机制反而成为了安全共享的前提。
导师的下一步建议: 太棒了!至此,我们已经通过 VAX/VMS 彻底走完了 ”虚拟化 (Virtualization)” 这第一大支柱的全部旅程,从 CPU 调度一直到内存和交换空间管理的顶峰。 根据您的学习进度,接下来我们将要进入本书最具挑战性、也最让程序员头疼的第二大支柱:”并发 (Concurrency)”。我们将面临多线程环境下的竞态条件、锁和条件变量。