缺页中断(Page Fault)详解
缺页中断是操作系统中内存管理的关键机制,当进程访问的虚拟内存页面不在物理内存(RAM)中时,由 MMU(内存管理单元) 触发 CPU 异常,操作系统通过中断处理程序将缺失的页面从磁盘(如交换空间或文件系统)加载到内存,使进程继续执行。
一. 缺页中断的触发条件
CPU 访问虚拟地址时,MMU 检查页表发现以下情况会触发缺页中断:
页表项不存在(Invalid Page):页面未分配或已被释放。
页面不在物理内存(Present Bit = 0):页面在交换空间或磁盘文件中。
权限不足(Protection Fault):例如用户程序试图写入只读页面。
二. 缺页中断的处理流程
- CPU 捕获异常
MMU 发现页面无效,触发 缺页异常(Page Fault Exception)。
CPU 保存当前上下文(寄存器、程序计数器),切换到内核模式。
- 操作系统处理中断
内核的 缺页中断处理程序 被调用,检查以下信息:
- 触发缺页的 虚拟地址(通过 CR2 寄存器获取)。
- 缺页原因(读/写/执行权限、页面是否存在)。
- 分类处理缺页类型
- 硬缺页(Hard Page Fault):
页面在磁盘(交换空间或文件),需从磁盘加载到内存(I/O 操作,速度慢)。
- 软缺页(Soft Page Fault):
页面在物理内存但未映射到当前进程(如共享内存),只需更新页表。
- 无效缺页(Invalid Page Fault)
:
访问非法地址(如空指针),触发 段错误(Segmentation Fault),终止进程。
- 加载缺失页面
如果是硬缺页:
- 从磁盘读取页面到 物理内存帧(Page Frame)。
- 更新页表,标记页面为有效(Present Bit = 1)。
- 如果内存已满,触发 页面置换算法(如 LRU、FIFO)换出旧页面。
- 恢复进程执行
重新执行引发缺页的指令,此时页面已在内存,正常访问。
三. 缺页中断的影响
性能开销:
- 硬缺页涉及磁盘 I/O,速度比内存慢 105~106 倍,可能导致进程阻塞。
- 频繁缺页(Thrashing)会显著降低系统性能。
内存利用率优化:
- 通过 按需分页(Demand Paging) 减少内存浪费,仅加载实际使用的页面。
四. 实际应用示例
(1)Linux 中的缺页中断处理
缺页中断入口:arch/x86/mm/fault.c → do_page_fault()。
主要逻辑:
if (页表项无效) {if (地址合法) {分配新页面或从磁盘加载;} else {发送 SIGSEGV 信号杀死进程; // Segmentation Fault}
}
(2)编程中的常见触发场景
访问未初始化的指针(触发无效缺页):
int *ptr = NULL;
*ptr = 42; // 触发段错误
动态内存分配(malloc):
首次访问分配的内存时触发软/硬缺页(实际分配物理页面)。
五. 如何减少缺页中断?
- 优化内存访问局部性:减少随机内存访问(如遍历多维数组时按行操作)。
- 预加载(Prefetching):提前加载可能需要的页面。
- 调整页面大小:大页(Huge Pages)减少缺页次数(但增加内部碎片)。
- 避免内存抖动(Thrashing):确保物理内存足够容纳工作集。
六. 相关概念扩展
- 页面置换算法:LRU、FIFO、Clock 算法等。
- 写时复制(Copy-on-Write):子进程共享父进程页面,仅在写入时触发缺页。
- 内存映射文件(mmap):文件直接映射到虚拟内存,访问时按需加载。