分段(Segmentation)
按逻辑划分内存,每个段对应程序的一个逻辑单元(代码段、数据段、栈段等)。
- 地址 = 段号 + 段内偏移
- 段长度可变,符合程序逻辑结构
- 优点:便于共享和保护(比如代码段只读)
- 缺点:外部碎片——段大小不一,内存里会出现零散的空洞,难以利用
分页(Paging)
把物理内存和虚拟地址空间都切成固定大小的块(页框/页,通常 4KB)。
- 地址 = 页号 + 页内偏移
- 通过页表把虚拟页号映射到物理页框号
- 优点:无外部碎片,内存利用率高
- 缺点:内部碎片(最后一页可能没用满);页表本身占内存,多级页表解决大地址空间问题
TLB(快表):页表查询要访问内存,太慢。TLB 是硬件缓存,缓存最近用过的页表项,命中率通常 >99%,大幅加速地址转换。
段页式
结合两者:先分段,每段再分页。兼顾逻辑清晰和物理高效,现代 x86 基本就是这个模型(但 Linux 把段都设成 0 基址,实际上退化成纯分页)。
虚拟内存
核心思想:程序不需要全部装入内存才能运行,只把当前用到的页加载进来,其余放在磁盘(swap)。
- 每个进程有独立的虚拟地址空间,互相隔离
- 访问不在内存的页 → 缺页中断(Page Fault) → OS 从磁盘调入该页
- 如果内存满了,需要先置换一个旧页出去
好处:
- 程序可以比物理内存大
- 进程隔离,安全
- 多进程共享物理内存(写时复制 COW)
页面置换算法
内存满了,选哪个页换出去?
| 算法 | 思路 | 特点 |
|---|---|---|
| OPT(最优) | 换出未来最长时间不用的页 | 理论最优,实际不可实现(无法预知未来),用于评估基准 |
| FIFO | 换出最早进入内存的页 | 实现简单,但可能换出常用页;有 Belady 异常(增加页框反而缺页率上升) |
| LRU(最近最少使用) | 换出最久没被访问的页 | 性能接近 OPT,工程常用;精确实现需要时间戳或链表,开销较大 |
| Clock(时钟/二次机会) | 给每页一个访问位,循环扫描,访问位为 1 则清零跳过,为 0 则换出 | LRU 的近似实现,开销小,Linux 实际使用的是改进版 |
| LFU(最不常用) | 换出访问次数最少的页 | 对突发访问不友好,历史计数可能失真 |
工程实际:Linux 用的是改进版 Clock(active/inactive 两个链表),近似 LRU,兼顾性能和开销。
总结
分段解决逻辑组织,分页解决物理碎片,虚拟内存让程序突破物理内存限制,页面置换算法决定内存满时踢谁出去——LRU 最常用,Clock 是工程近似。