引言
在计算机发展的早期,物理内存极其昂贵且容量有限。如何在有限的内存中运行更大的程序、更多的进程,成为了操作系统设计的核心挑战。覆盖(Overlay) 和 交换(Swapping) 技术应运而生,它们是解决内存容量矛盾的两种经典方案。
1. 覆盖技术:程序内部的内存复用
1.1 产生背景
- 早期IBM PC仅有1MB内存,而程序可能需要数十MB
- 单道程序设计时代,内存只运行一道程序
- 程序整体必须装入内存才能运行
核心矛盾:程序大小 > 物理内存容量
1.2 核心思想
覆盖技术的核心是时间换空间:将程序划分为多个模块,根据调用关系,让不同时执行的模块共享同一块内存区域。
- 程序的调用关系形成一棵调用树
- 互斥调用的模块可以共享内存空间
- 程序员需要显式声明覆盖结构
1.3 技术详解
内存布局:内存分为固定区(存放公共部分如main函数,常驻内存)和若干覆盖区(存放互斥模块,动态装入)。 将程序分成多个段(模块),常用的段常驻内存,不常用的段按需调入调出。
┌─────────────────────────────────┐
│ 固定区 │ ← 常用段,调入后不再调出
├─────────────────────────────────┤
│ 覆盖区 0 │ ← 不常用段,按需调入调出
├─────────────────────────────────┤
│ 覆盖区 1 │ ← 不常用段,按需调入调出
├─────────────────────────────────┤
│ ... │
└─────────────────────────────────┘
实例分析:程序X的调用结构如下:
┌─────────────┐
│ 模块 A │ (8KB) - main函数
└──────┬──────┘
┌──────┴──────┐
┌─────────┐ ┌─────────┐
│ 模块 B │ │ 模块 C │ ← B和C互斥
│ (10KB) │ │ (8KB) │
└────┬────┘ └────┬────┘
┌─────────┐ ┌─────────┐
│ 模块 D │ │ 模块 E │ ← D、E互斥
│ (12KB) │ │ (4KB) │
└─────────┘ └─────────┘
覆盖区划分:
- 固定区:A = 8KB
- 覆盖区0:B或C,取max(10KB, 8KB) = 10KB
- 覆盖区1:D、E,取max(12KB, 4KB) = 12KB
- 总内存:8 + 10 + 12 = 30KB(不使用覆盖需52KB,节省42.3%)
实现机制:操作系统维护覆盖描述表,运行时检查目标模块是否已装入,未装入则执行换入换出操作。
1.4 优缺点
| 优点 | 缺点 |
|---|---|
| 显著减少内存占用 | 程序员负担重,需手动划分模块 |
| 适合早期单道程序系统 | 对用户不透明,增加编程复杂度 |
历史地位:覆盖技术已被虚拟内存取代,但其思想(按需加载)在动态链接库延迟加载中仍有体现。
2. 交换技术:进程级别的内存复用
2.1 产生背景
- 多道程序设计时代,内存同时运行多个进程
- 进程总数增多,内存可能无法容纳所有进程
- 某些进程暂时阻塞(如等待I/O),占用内存却不运行
核心矛盾:进程总数 × 平均内存需求 > 物理内存容量
2.2 核心思想
交换技术的核心是空间换时间:将暂时不能运行的进程整个换出到外存,腾出内存给其他进程使用;当被换出的进程重新具备运行条件时,再换入内存。
关键特点:
- 以整个进程为单位进行换入换出
- 由操作系统自动管理,对用户透明
- 与中级调度(内存调度)密切相关
2.3 技术详解
交换过程:
┌─────────────────────────────────────────────────────┐
│ 内存空间 │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ 进程1│ │ 进程2│ │ 进程3│ │ 进程4│ ← 运行中 │
│ │ PCB │ │ PCB │ │ PCB │ │ PCB │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │ │
│ 内存紧张 ↓ 触发交换 │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ 进程1│ │ 进程3│ │ 进程4│ ← 腾出空间 │
│ │ PCB │ │ PCB │ │ PCB │ │
│ └─────┘ └─────┘ └─────┘ │
└─────────────────────────────────────────────────────┘
│
↓ 换出(进程2)
┌─────────────────────────────────────────────────────┐
│ 外存空间 │
│ ┌─────────────────────────────┐ │
│ │ 进程2 │ │
│ │ (代码段 + 数据段 + 堆栈) │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
PCB常驻内存原则:进程被换出外存时,其PCB必须保留在内存中。原因:
- 操作系统需通过PCB管理所有进程(即使被换出)
- PCB记录进程状态(就绪/阻塞/挂起)
- 换入时通过PCB找到进程在外存的位置
交换的三个关键问题:
| 问题 | 答案 |
|---|---|
| 换出到什么位置? | 对换区(连续分配,追求换入换出速度) |
| 什么时候交换? | 内存紧张、缺页率升高时 |
| 换出什么进程? | 优先换出阻塞进程、低优先级进程 |
对换区vs文件区:
- 文件区:存放普通文件,离散分配,追求空间利用率
- 对换区:存放换出的进程,连续分配,追求换入换出速度
2.4 优缺点
| 优点 | 缺点 |
|---|---|
| 操作系统自动管理,对用户透明 | 换入换出I/O开销大 |
| 支持多进程并发运行 | 需要硬件支持(MMU) |
现代应用:交换技术演化为虚拟内存,现代系统使用SSD作为对换区提升性能。
3. 覆盖与交换的对比分析
| 对比维度 | 覆盖技术 | 交换技术 |
|---|---|---|
| 作用范围 | 同一程序/进程内部 | 不同进程/作业之间 |
| 换入换出单位 | 程序模块(函数/段) | 整个进程 |
| 实现者 | 程序员显式声明 | 操作系统自动管理 |
| 对用户透明度 | 不透明,增加编程负担 | 透明,用户无感知 |
| 实现复杂度 | 较简单 | 复杂,需硬件支持 |
| 性能开销 | 运行时换入换出开销 | I/O传输开销 |
| 适用场景 | 早期单道程序系统 | 现代多道程序系统 |
| 历史地位 | 已基本淘汰 | 广泛使用,演化为虚拟内存 |
核心要点:
- 覆盖技术解决程序过大问题,交换技术解决进程过多问题
- 交换技术中PCB必须常驻内存,这是理解进程管理的关键
- 对换区采用连续分配,牺牲空间利用率换取交换速度
- 交换技术是虚拟内存的前身,现代系统将其与请求分页结合