《操作系统导论》第16章:分段 - 深度知识架构
1. 核心矛盾 (The Crucial Problem)
如何在支持巨大且稀疏的虚拟地址空间的同时,避免因物理内存必须连续存放整个地址空间而导致的巨大空间浪费(内部碎片)?
2. 核心概念 (Core Concepts)
- 分段 (Segmentation):
- 定义:将程序的地址空间划分为几个逻辑上独立、长度可变的连续区域(通常为代码段、堆段和栈段),并为每个区域分配独立的基址和界限寄存器。
- 角色:内存利用率的"拯救者"。它打破了地址空间必须在物理内存中作为单一连续整体存放的限制,允许操作系统将不同的段放在物理内存的不同位置。
- 段错误 (Segmentation Fault):
- 定义:当程序试图访问超出其合法段界限的内存地址,或以非法方式(如写入只读段)访问内存时,硬件触发的异常。
- 角色:系统的"执法者"。这个术语一直沿用至今,它是硬件配合操作系统保护内存隔离的直接体现。
- 外部碎片 (External Fragmentation):
- 定义:物理内存中充满了许多大小不一的空闲小洞,导致虽然总的空闲空间足够,但无法满足某个需要大块连续内存的分配请求。
- 角色:分段机制带来的"新恶魔"。由于每个段的大小不同,物理内存的分配和释放变得极不规则,这是变长内存分配的致命宿命。
- 紧凑 (Compaction):
- 定义:操作系统暂停运行的进程,将它们在物理内存中的段复制、移动到连续的区域,从而将散落的空闲小洞合并成大块连续空闲空间的过程。
- 角色:解决外部碎片的"重型武器"。代价极其高昂,极其消耗中央处理器 (Central Processing Unit, CPU) 时间。
3. 逻辑演进 (Logical Evolution)
为了解决地址空间中未使用的巨大空洞被原封不动搬进物理内存的问题,计算机科学家经历了如下推演:
- 最初的方案(泛化基址和界限):既然栈和堆之间有大片空白,那我们就不再为整个地址空间提供单一的基址/界限对,而是为每一个逻辑段(代码、堆、栈)提供一对寄存器。当发生地址转换时,内存管理单元 (Memory Management Unit, MMU) 硬件根据虚拟地址的高位(如前两位)判断它属于哪个段,然后加上对应段的基址。
- 解决的问题:完美消除了堆和栈之间巨大空洞带来的物理内存浪费(因为未使用的地址空间根本不会被分配物理内存),成功支持了稀疏地址空间。
- 演进与修补 1(反向增长的栈):栈的增长方向是向下的(向低地址增长)。这导致简单的"基址+偏移量"算术会出错。
- 成熟方案:硬件在段寄存器中增加一个特殊的"方向位",用于记录段是向上还是向下增长。硬件据此调整反向偏移量的计算方法。
- 演进与修补 2(利用隔离实现共享):设计者发现,既然代码已经独立成段,而多个运行同一程序的进程其代码段是完全相同的。
- 成熟方案:在硬件段寄存器中增加"保护位 (Protection Bit)"。将代码段标记为"只读-可执行",这样操作系统就可以将一个物理内存中的代码段,映射到多个进程的虚拟地址空间中,大大节省了内存。
- 最终的遗留挑战(外部碎片):分段完美解决了"内部碎片",但由于各个段的大小是任意可变的,频繁的分配和释放物理内存,导致物理内存千疮百孔,出现了无法轻易解决的外部碎片问题。
4. 机制与策略 (Mechanisms vs. Policies)
- 底层的"实现手段"(机制 - Mechanisms):
- 硬件分段映射:MMU 通过截取虚拟地址的高位来确定段号(Segment ID),用低位作为偏移量(Offset)去和界限寄存器比较,最后加上基址寄存器完成转换。
- 上下文切换支持:操作系统 (Operating System, OS) 在进程切换时,必须保存和恢复每个进程的多组段寄存器(基址、界限、方向位、保护位)。
- 上层的"决策逻辑"(策略 - Policies):
- 空闲空间管理策略:当进程请求分配一个新段时,OS 如何在充满碎片的物理内存中找到一块合适的空间?这就需要上层的策略算法,如最优匹配 (Best-fit)、最坏匹配 (Worst-fit)、首次匹配 (First-fit) 或伙伴算法 (Buddy Algorithm)。
5. 设计折衷 (Design Trade-offs)
- 牺牲"空间分配的极简性",换取"高内存利用率与逻辑模块化":分段机制使得内存分配从原先简单的"分配一个大块"变成了极具挑战的"管理无数个变长小块"。操作系统被迫引入复杂的空闲列表算法甚至代价高昂的内存紧凑操作。但这换来了极其可观的内存节省(不分配无用空间),并且自然而然地通过逻辑分段实现了代码共享和细粒度权限保护。
6. 关键洞察 (Key Insights)
- 如果有一千个解决方案,就说明没有一个是完美的:在应对分段带来的"外部碎片"问题时,学术界和工业界发明了成百上千种空闲空间分配算法。这恰恰印证了一个深刻的工程洞察:这是一个在数学层面无解的几何拼接难题。唯一真正的解决办法不是优化算法,而是从根本上改变规则——永远不要分配不同大小的内存块(这直接导向了未来的"分页"技术)。
- 逻辑拆分催生了共享的可能:原先的地址空间是一个黑盒,OS 不知道里面装的是什么。分段迫使我们将黑盒拆分为具有特定逻辑含义的部分(代码、栈、数据)。这种逻辑上的"看透",让操作系统能够赋予它们不同的读写属性,意外地为"跨进程内存共享"打开了方便之门。
导师的下一步建议:
分段通过为每个逻辑段独立分配物理内存解决了内部碎片问题,但变长段的频繁分配与释放导致了新的外部碎片难题——物理内存中充满无法利用的小洞。下一章将深入操作系统内部,探讨各种空闲空间管理算法(如最优匹配、首次匹配、伙伴系统等)如何应对外部碎片的挑战。