2. 物理内存与虚拟地址空间:MMU与页表机制、物理页框与虚拟页、缺页异常处理流程
现代操作系统通过虚拟内存技术,为每个进程提供独立的、连续的虚拟地址空间,而底层物理内存则被划分为固定大小的物理页框(Page Frame)。本章深入剖析从虚拟地址到物理地址的转换核心——MMU与页表机制,并详细拆解缺页异常(Page Fault)的完整处理流程,为后续KSM与透明大页(THP)的性能调优奠定坚实的硬件与内核基础。
2.1 物理页框与虚拟页
物理内存被内核划分为固定大小的物理页框(通常为4KB),而进程的虚拟地址空间则被划分为同样大小的虚拟页(Virtual Page)。映射关系由页表维护。
| 概念 | 定义 | 大小 | 管理主体 |
|---|---|---|---|
| 物理页框 | 物理内存的最小分配单元,是硬件可寻址的实际存储区域 | 通常 4KB(x86_64 默认) | 内核伙伴系统(Buddy Allocator) |
| 虚拟页 | 进程虚拟地址空间中的连续区域,可能映射到物理页框或磁盘交换空间 | 与物理页框大小一致(4KB) | 内核内存管理(MM) |
| 页框号(PFN) | 物理页框的索引编号,物理地址右移 PAGE_SHIFT 位得到 | — | 硬件/内核 |
关键理解:虚拟页是进程视角的“内存”,物理页框是硬件视角的“内存”。一个虚拟页可以映射到不同的物理页框,也可以不映射(未分配或换出)。KSM 的核心工作就是合并内容相同的物理页框,从而节省物理内存。
2.2 MMU与页表机制
内存管理单元(MMU)是CPU内部的硬件模块,负责将虚拟地址(VA)转换为物理地址(PA)。转换过程依赖页表(Page Table)——一种由内核维护的多级数据结构。
2.2.1 多级页表结构(x86_64 4级页表)
为了节省页表占用的物理内存,x86_64 架构采用 4 级页表(PML4、PDPT、PD、PT)。虚拟地址被划分为多个位段,每段索引一级页表。
虚拟地址分解(48位,4级页表):
| 63–48 | 47–39 (9 bit) | 38–30 (9 bit) | 29–21 (9 bit) | 20–12 (9 bit) | 11–0 (12 bit) | |:---:|:---:|:---:|:---:|:---:|:---:| | 符号扩展 | PML4 索引 | PDPT 索引 | PD 索引 | PT 索引 | 页内偏移 |
| 63–48 | 47–39 (9 bit) | 38–30 (9 bit) | 29–21 (9 bit) | 20–12 (9 bit) | 11–0 (12 bit) | |:---:|:---:|:---:|:---:|:---:|:---:| | 符号扩展 | PML4 索引 | PDPT 索引 | PD 索引 | PT 索引 | 页内偏移 |
转换过程:MMU 从 CR3 寄存器获取 PML4 基址,依次索引 4 级页表,最终找到物理页框基址,加上页内偏移得到物理地址。
2.2.2 页表项(PTE)标志位
每个页表项不仅包含物理页框号(PFN),还包含关键的权限和状态标志位,直接影响缺页异常和性能调优。
| 标志位 | 名称 | 含义 | 对调优的影响 |
|---|---|---|---|
| P | Present | 页是否在物理内存中(0 表示缺页或换出) | 缺页异常触发条件 |
| R/W | Read/Write | 0 只读,1 可读写 | 写时复制(CoW)依赖此位 |
| U/S | User/Supervisor | 0 仅内核可访问,1 用户态可访问 | 内核/用户空间隔离 |
| A | Accessed | 硬件自动置位,表示页被访问过 | KSM 扫描、页面回收策略 |
| D | Dirty | 硬件自动置位,表示页被写过 | 换出时需写回磁盘 |
| PS | Page Size | 1 表示大页(2MB/1GB) | 透明大页(THP)启用标志 |
性能陷阱:TLB(Translation Lookaside Buffer)是 MMU 内部的页表缓存。当使用 4KB 小页时,TLB 覆盖范围有限;启用透明大页(2MB)可显著提高 TLB 命中率,但会增加内存碎片和回收延迟。这是后续 THP 调优的核心矛盾。
2.3 缺页异常处理流程
当 CPU 访问一个虚拟地址,MMU 在页表中查找对应的 PTE,如果 Present 位为 0,则触发缺页异常(Page Fault)。Linux 内核的缺页异常处理函数(do_page_fault)根据异常类型执行不同的处理路径。
2.3.1 缺页异常分类
| 类型 | 触发条件 | 内核处理动作 | 性能影响 |
|---|---|---|---|
| 主要缺页 | 页不在内存,需要从磁盘交换区(swap)读入 | 发起 I/O,进程睡眠等待 | 高延迟(毫秒级),严重影响性能 |
| 次要缺页 | 页不在内存,但物理页框已分配(如共享内存、匿名页首次访问) | 快速建立映射,无需 I/O | 低延迟(微秒级) |
| 写时复制缺页 | 访问只读共享页并尝试写入 | 复制物理页框,更新 PTE 为可写 | 中等延迟,fork() 后常见 |
| 无效缺页 | 访问未映射的地址(段错误) | 发送 SIGSEGV 信号 | 程序崩溃 |
2.3.2 缺页异常处理流程详解
以下流程图展示了从虚拟地址访问到缺页处理完成的完整路径:
2.3.3 缺页异常与性能调优的关联
- 主要缺页(Major Page Fault):是性能杀手,应极力避免。频繁的主要缺页意味着物理内存不足,系统正在大量使用交换空间。此时应考虑增加物理内存或优化内存占用(如启用 KSM 合并重复页)。
- 次要缺页(Minor Page Fault):开销较小,但大量发生仍会增加内核路径开销。透明大页(THP)通过减少页表项数量,可降低次要缺页的频率。
- 写时复制缺页(CoW Page Fault):在
fork()后大量出现。KSM 的合并操作会触发 CoW,导致短暂性能下降,需要在内存节省和 CPU 开销之间权衡。
调优观察点:使用
sar -B 或 /proc/vmstat 监控 pgfault、pgmajfault、pgsteal_kswapd 等指标。如果 pgmajfault 持续不为 0,说明内存存在压力,KSM 或 THP 的调优可能带来收益。
2.4 本章小结
- 物理页框是硬件分配单元,虚拟页是进程视角的抽象,二者通过页表建立映射。
- MMU 负责硬件地址转换,多级页表在 x86_64 上节省了页表占用的物理内存。
- 缺页异常分为主要缺页、次要缺页和写时复制缺页,内核根据 PTE 标志位和 VMA 属性执行不同的处理路径。
- 理解缺页异常的分类和开销,是后续调优 KSM(减少物理页框数量)和 THP(增大映射粒度)的基础。