蔚淦丞
发布于 2026-09-13 / 7 阅读
0
0

SWAP交换分区、页面置换算法

1. 核心整体关系

页面置换算法 和 Swap 是配套机制:

  • 页面置换算法:负责内存紧张时,挑选哪一页淘汰

  • Swap:负责把淘汰下来、无磁盘原生副本的页面,落地到磁盘保存

缺页异常 + 无空闲物理页 → 置换算法选冷页淘汰 → 根据页面类型决定是否写 Swap。

2. 四大经典页面置换算法(完整理论)

OPT 最优置换算法

理论最优,淘汰未来最长时间不访问的页面。 缺页率最低,但需要预知未来访问序列,无法工程实现,仅作为理论评测标准。

FIFO 先进先出

按照页面载入内存顺序淘汰最旧页面。 缺点:不区分冷热,长期高频使用的老页也会被淘汰;存在 Belady 异常(内存页框越多,缺页次数反而增加)。

LRU 最近最少使用

基于局部性原理:过去很久没用 → 未来大概率不用。 淘汰最近最少访问的页面,实际效果最贴合业务行为。 缺点:严格 LRU 需要维护完整时间有序链表,开销巨大,操作系统不采用。

Clock 时钟算法(Linux 工程实现)

LRU 的轻量化近似实现。 利用硬件 A 访问位 环形扫描页面:

  • A=1:近期访问过,清零,保留

  • A=0:长期未访问,直接淘汰 开销极低,是 Linux 内核真实回收的核心思路。

3. Linux 真实内存回收机制

  1. 维护两条链表

  • active 活跃链表:热页、高频访问

  • inactive 非活跃链表:冷页、优先回收

  1. 硬件自动维护位

  • A 访问位:判断页面冷热

  • D 脏位:判断页面是否需要写盘

  1. kswapd 后台线程 内存低于水位线提前后台预回收,不等内存彻底撑满,避免系统卡顿。

4. 系统两类页面 + 回收规则

1)文件页(依托 ELF 原始磁盘副本)

.text / .rodata

PTE 永久只读,用户态永远无法写入。 硬件无法触发写操作 → D 脏位永远为 0,永远是干净页 回收规则:直接释放物理内存,无需写盘、无需 Swap

.data(可读写全局变量)

初始为私有文件映射:

  • 未写:D=0 干净页,回收直接释放

  • 发生写操作:触发私有映射的 COW,内核复制出新物理页;新页面脱离文件映射,转为匿名页
    👉 重点: 原始 ELF 文件页永远干净、永远不改;修改产生的新页是匿名页,后续回收走 Swap,绝不覆盖原始 ELF 程序文件

2)匿名页(Swap 唯一服务对象)

包含:堆、用户栈、.bss、COW 复制出来的 data 新页 特性:无原生磁盘文件副本

回收铁律:

匿名页无论 D=0 干净 / D=1 脏,只要被 LRU/Clock 选中回收,必须写入 Swap

原因: 匿名页没有磁盘备份,干净只是代表「本次载入后没修改」,不代表磁盘有数据,不写 Swap 数据直接丢失。

5. 页面换出 PageOut 完整流程

  1. 内存紧张,kswapd 触发页面回收

  2. 通过 Clock 近似 LRU 筛选最冷页面

  3. 分类处理:

  • text/rodata/data 干净文件页:直接释放

  • 被写过的 data:已经转为匿名页 → 写入 Swap

  • 堆 / 栈 /bss 匿名页:一律写入 Swap

  1. PTE 置 Present=0,记录 Swap 磁盘偏移

  2. 释放物理内存

6. 页面换入 PageIn 完整流程

  1. 进程访问已换出的虚拟地址

  2. MMU 检测 Present=0,触发缺页异常

  3. 内核判断页面存在 Swap 分区

  4. 分配空闲物理页,从磁盘读回页面数据

  5. 修复 PTE:回填物理页框号、Present=1

  6. 移入活跃链表,程序继续执行

7. 终极总结(面试直接背诵)

  1. 置换算法负责选淘汰页,Swap 负责持久化无副本匿名页

  2. text、rodata 只读无脏页,回收直接丢弃;data 写后通过 COW 转为匿名页。

  3. 文件页依靠 ELF 原生副本,无需 Swap;Swap 只服务匿名页

  4. Linux 放弃严格 LRU,使用 Clock 近似 LRU,兼顾性能与效果。

  5. 匿名页无论干净脏,回收必落 Swap,因为天生无磁盘备份。


评论