内存管理
内存管理的目标是在多个进程间高效、安全地分配物理内存,并提供地址隔离与保护。从早期的连续分配,到现代以分页为主的方案,核心都是解决"如何把虚拟地址映射到物理地址"以及"如何减少碎片"。
连续分配
最简单的方案把进程整个装入一块连续物理区。常见三种放置策略:
- 首次适配(First-Fit):从低地址开始找第一个足够大的空闲块,速度较快。
- 最佳适配(Best-Fit):找最小但足够的空闲块,减少大块浪费,但会产生大量小碎片。
- 最坏适配(Worst-Fit):找最大空闲块切,试图保留较多大块,实际效果常最差。
连续分配实现简单,只用一个基址寄存器即可重定位,缺点是会产生外部碎片,需要通过compaction(内存紧缩)定期整理。
分页与页表
分页把虚拟地址空间和物理内存都切成等长页面(典型 4KB),通过页表把虚拟页映射到物理页帧(称为page frame)。优点是消除了外部碎片,任意物理页帧都可使用;代价是引入了内部碎片(页内未用部分)与页表本身的开销。
地址转换硬件(MMU)过程:
虚拟地址 = [ 页号 VPN | 页内偏移 offset ]
物理地址 = [ 页帧号 PFN | 页内偏移 offset ]
PFN = 页表[VPN]
多级页表
单级页表的大小与虚拟地址空间成正比,64 位系统无法承受。多级页表按页号分层,只为实际使用的页区间建立子表,显著节省内存。x86-64 使用四级页表(PML4 → PDPT → PD → PT),ARM64 类似。
分段
分段以"逻辑段"为单位(代码段、数据段、栈段),每段长度可变,提供开发者视角的地址空间。段号+段内偏移构成虚拟地址。段的最大问题是外部碎片与段长不固定带来的管理复杂。
段页式
实际系统往往结合两者:先按段划分逻辑空间,再在段内分页。程序员与编译器看到段,MMU 看到页。这样既保留逻辑清晰,又得到分页的物理优势,Intel x86 架构就提供这种机制。
碎片小结
| 类型 | 出现在 | 解决方案 |
|---|---|---|
| 内部碎片 | 固定大小分配单元内未用部分 | 分页(无法完全消除,只能减小页大小) |
| 外部碎片 | 空闲块零散、不连续 | 紧缩(连续分配)或非连续分配(分页) |
现代通用 OS 几乎都以分页为底层机制,再叠加换出与共享映射等高级特性。