这是"操作系统系列教程"的第三十一篇。上一篇我们讲了页表,知道了虚拟地址如何通过页表转换为物理地址。但有一个关键问题还没有回答:如果程序访问的页不在物理内存中 ,操作系统该怎么办?答案就是------缺页中断。
一个"找不到书"的场景
先来想象一个场景。你去图书馆借书,拿着索书号来到书架前,却发现书不在书架上。这时你会怎么做?
你不会直接放弃,而是会去找图书管理员。管理员会去书库(密集书库或仓库)找到这本书,把它放到书架上,然后告诉你:"现在可以借了。"
操作系统处理"页不在内存"的过程,几乎一模一样:
- 程序访问一个虚拟地址;
- 页表项的有效位为 0,表示该页不在物理内存中;
- CPU 触发一个缺页中断(Page Fault);
- 操作系统暂停当前进程,从磁盘把缺失的页加载到内存;
- 更新页表,重新执行刚才那条指令;
- 程序继续运行,就好像什么都没发生过。
这个过程,就是缺页中断处理。
缺页中断是虚拟内存的核心机制。没有它,虚拟内存就无法实现"用磁盘扩充内存"的效果。但缺页中断也有代价------磁盘访问比内存访问慢几个数量级,频繁的缺页中断会严重拖慢系统。
这篇文章,我们就来把"缺页中断"这件事讲清楚。
说明:本文涉及缺页中断、页面置换、有效位等概念。初学者如果遇到暂时看不懂的术语,可以先跳过细节,重点理解"程序访问的页不在内存时,操作系统从磁盘加载该页,然后重新执行指令"这一核心思想。
一、缺页中断到底是什么?
1.1 从"有效位"说起
在页表项中,有一个关键字段:有效位(Valid Bit)。
| 有效位 | 含义 |
|---|---|
| 1 | 该页在物理内存中,可以正常访问 |
| 0 | 该页不在物理内存中(可能在磁盘上,或从未被加载) |
当 CPU 访问一个虚拟地址时,MMU 会查页表:
- 如果有效位为 1,直接得到物理页框号,正常访问;
- 如果有效位为 0,MMU 触发缺页中断,把控制权交给操作系统。
1.2 缺页中断的定义
给出一个正式的定义:
缺页中断(Page Fault)是当程序访问的虚拟页不在物理内存中时,由 CPU 的 MMU 触发的一种异常。操作系统捕获该异常后,从磁盘把缺失的页加载到物理内存,更新页表,然后重新执行触发异常的指令。
这个定义里有四个关键点:
- 页不在内存:有效位为 0;
- MMU 触发异常:这是硬件自动完成的;
- 操作系统处理:从磁盘加载页,更新页表;
- 重新执行指令:让程序感觉不到中断。
1.3 缺页中断在系统中的位置
#mermaid-svg-DV4nRNbdRZ9kR9BJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .error-icon{fill:#552222;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .marker.cross{stroke:#333333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ p{margin:0;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .cluster-label text{fill:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .cluster-label span{color:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .cluster-label span p{background-color:transparent;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .label text,#mermaid-svg-DV4nRNbdRZ9kR9BJ span{fill:#333;color:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .node rect,#mermaid-svg-DV4nRNbdRZ9kR9BJ .node circle,#mermaid-svg-DV4nRNbdRZ9kR9BJ .node ellipse,#mermaid-svg-DV4nRNbdRZ9kR9BJ .node polygon,#mermaid-svg-DV4nRNbdRZ9kR9BJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .rough-node .label text,#mermaid-svg-DV4nRNbdRZ9kR9BJ .node .label text,#mermaid-svg-DV4nRNbdRZ9kR9BJ .image-shape .label,#mermaid-svg-DV4nRNbdRZ9kR9BJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .rough-node .label,#mermaid-svg-DV4nRNbdRZ9kR9BJ .node .label,#mermaid-svg-DV4nRNbdRZ9kR9BJ .image-shape .label,#mermaid-svg-DV4nRNbdRZ9kR9BJ .icon-shape .label{text-align:center;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .node.clickable{cursor:pointer;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .arrowheadPath{fill:#333333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DV4nRNbdRZ9kR9BJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DV4nRNbdRZ9kR9BJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DV4nRNbdRZ9kR9BJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .cluster text{fill:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .cluster span{color:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DV4nRNbdRZ9kR9BJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .icon-shape,#mermaid-svg-DV4nRNbdRZ9kR9BJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .icon-shape p,#mermaid-svg-DV4nRNbdRZ9kR9BJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .icon-shape .label rect,#mermaid-svg-DV4nRNbdRZ9kR9BJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DV4nRNbdRZ9kR9BJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DV4nRNbdRZ9kR9BJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DV4nRNbdRZ9kR9BJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
程序访问虚拟地址
MMU 查页表
有效位是否为 1
正常访问物理内存
触发缺页中断
操作系统处理
从磁盘加载页
更新页表
重新执行指令
图 1:缺页中断在系统中的位置。 页不在内存时,MMU 触发异常,操作系统处理。
二、为什么需要缺页中断?
2.1 虚拟内存的"按需加载"
虚拟内存的核心思想是:程序不需要一次性把所有页都加载到内存,只加载当前用到的页 。这就是按需加载(Demand Paging)。
按需加载的好处:
- 启动快:程序启动时不需要加载全部代码和数据;
- 内存省:不常用的页可以留在磁盘上;
- 支持大程序:程序可以比物理内存大。
但按需加载也带来一个问题:当程序访问一个尚未加载的页时,必须有一种机制把它加载进来。这就是缺页中断的作用。
2.2 缺页中断的必要性
没有缺页中断,按需加载就无法实现。操作系统无法知道程序何时需要哪个页,只有程序真正访问时,才能通过缺页中断"按需"加载。
#mermaid-svg-VFyVlcLvuRrd5HpD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VFyVlcLvuRrd5HpD .error-icon{fill:#552222;}#mermaid-svg-VFyVlcLvuRrd5HpD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VFyVlcLvuRrd5HpD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VFyVlcLvuRrd5HpD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VFyVlcLvuRrd5HpD .marker.cross{stroke:#333333;}#mermaid-svg-VFyVlcLvuRrd5HpD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VFyVlcLvuRrd5HpD p{margin:0;}#mermaid-svg-VFyVlcLvuRrd5HpD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD .cluster-label text{fill:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD .cluster-label span{color:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD .cluster-label span p{background-color:transparent;}#mermaid-svg-VFyVlcLvuRrd5HpD .label text,#mermaid-svg-VFyVlcLvuRrd5HpD span{fill:#333;color:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD .node rect,#mermaid-svg-VFyVlcLvuRrd5HpD .node circle,#mermaid-svg-VFyVlcLvuRrd5HpD .node ellipse,#mermaid-svg-VFyVlcLvuRrd5HpD .node polygon,#mermaid-svg-VFyVlcLvuRrd5HpD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VFyVlcLvuRrd5HpD .rough-node .label text,#mermaid-svg-VFyVlcLvuRrd5HpD .node .label text,#mermaid-svg-VFyVlcLvuRrd5HpD .image-shape .label,#mermaid-svg-VFyVlcLvuRrd5HpD .icon-shape .label{text-anchor:middle;}#mermaid-svg-VFyVlcLvuRrd5HpD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VFyVlcLvuRrd5HpD .rough-node .label,#mermaid-svg-VFyVlcLvuRrd5HpD .node .label,#mermaid-svg-VFyVlcLvuRrd5HpD .image-shape .label,#mermaid-svg-VFyVlcLvuRrd5HpD .icon-shape .label{text-align:center;}#mermaid-svg-VFyVlcLvuRrd5HpD .node.clickable{cursor:pointer;}#mermaid-svg-VFyVlcLvuRrd5HpD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VFyVlcLvuRrd5HpD .arrowheadPath{fill:#333333;}#mermaid-svg-VFyVlcLvuRrd5HpD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VFyVlcLvuRrd5HpD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VFyVlcLvuRrd5HpD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VFyVlcLvuRrd5HpD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VFyVlcLvuRrd5HpD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VFyVlcLvuRrd5HpD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VFyVlcLvuRrd5HpD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VFyVlcLvuRrd5HpD .cluster text{fill:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD .cluster span{color:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VFyVlcLvuRrd5HpD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VFyVlcLvuRrd5HpD rect.text{fill:none;stroke-width:0;}#mermaid-svg-VFyVlcLvuRrd5HpD .icon-shape,#mermaid-svg-VFyVlcLvuRrd5HpD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VFyVlcLvuRrd5HpD .icon-shape p,#mermaid-svg-VFyVlcLvuRrd5HpD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VFyVlcLvuRrd5HpD .icon-shape .label rect,#mermaid-svg-VFyVlcLvuRrd5HpD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VFyVlcLvuRrd5HpD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VFyVlcLvuRrd5HpD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VFyVlcLvuRrd5HpD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 按需加载
启动快
内存省
支持大程序
需要缺页中断
按需加载缺失的页
图 2:缺页中断是实现按需加载的关键机制。
2.3 缺页中断的类型
缺页中断可以分为几种类型:
| 类型 | 说明 | 处理方式 |
|---|---|---|
| 主缺页 | 页从未被加载过 | 从磁盘加载 |
| 次缺页 | 页曾被加载但被换出 | 从交换空间加载 |
| 无效访问 | 访问了非法地址 | 终止进程 |
| 保护错误 | 访问权限不足 | 终止进程或发送信号 |

图 3:缺页中断的四种类型。
三、缺页中断的处理流程
3.1 完整流程图
物理内存 磁盘 页表 操作系统 MMU 程序 物理内存 磁盘 页表 操作系统 MMU 程序 #mermaid-svg-inOEDBJMVqtWgpfn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-inOEDBJMVqtWgpfn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-inOEDBJMVqtWgpfn .error-icon{fill:#552222;}#mermaid-svg-inOEDBJMVqtWgpfn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-inOEDBJMVqtWgpfn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-inOEDBJMVqtWgpfn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-inOEDBJMVqtWgpfn .marker.cross{stroke:#333333;}#mermaid-svg-inOEDBJMVqtWgpfn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-inOEDBJMVqtWgpfn p{margin:0;}#mermaid-svg-inOEDBJMVqtWgpfn .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-inOEDBJMVqtWgpfn text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-inOEDBJMVqtWgpfn .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-inOEDBJMVqtWgpfn .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-inOEDBJMVqtWgpfn .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-inOEDBJMVqtWgpfn .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-inOEDBJMVqtWgpfn #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-inOEDBJMVqtWgpfn .sequenceNumber{fill:white;}#mermaid-svg-inOEDBJMVqtWgpfn #sequencenumber{fill:#333;}#mermaid-svg-inOEDBJMVqtWgpfn #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-inOEDBJMVqtWgpfn .messageText{fill:#333;stroke:none;}#mermaid-svg-inOEDBJMVqtWgpfn .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-inOEDBJMVqtWgpfn .labelText,#mermaid-svg-inOEDBJMVqtWgpfn .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-inOEDBJMVqtWgpfn .loopText,#mermaid-svg-inOEDBJMVqtWgpfn .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-inOEDBJMVqtWgpfn .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-inOEDBJMVqtWgpfn .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-inOEDBJMVqtWgpfn .noteText,#mermaid-svg-inOEDBJMVqtWgpfn .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-inOEDBJMVqtWgpfn .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-inOEDBJMVqtWgpfn .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-inOEDBJMVqtWgpfn .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-inOEDBJMVqtWgpfn .actorPopupMenu{position:absolute;}#mermaid-svg-inOEDBJMVqtWgpfn .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-inOEDBJMVqtWgpfn .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-inOEDBJMVqtWgpfn .actor-man circle,#mermaid-svg-inOEDBJMVqtWgpfn line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-inOEDBJMVqtWgpfn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt有空闲页框没有空闲页框 alt地址合法地址非法 访问虚拟地址查询页表项有效位为 0触发缺页中断检查地址是否合法查找空闲物理页框读取缺失的页返回页数据放入空闲页框更新页表项(有效位=1)重新执行指令执行页面置换写回脏页(如果需要)读取缺失的页返回页数据放入页框更新页表项重新执行指令终止进程(段错误)
图 4:缺页中断的完整处理流程。 从触发异常到重新执行指令。
3.2 详细步骤
- 程序访问虚拟地址:CPU 发出虚拟地址;
- MMU 查页表:发现有效位为 0;
- 触发缺页中断:CPU 保存当前上下文,切换到内核态;
- 操作系统检查地址合法性:判断地址是否在进程的合法地址空间内;
- 地址非法:终止进程(如段错误);
- 地址合法 :
- 查找空闲物理页框;
- 如果没有空闲页框,执行页面置换,换出某个页;
- 从磁盘读取缺失的页;
- 把页放入物理页框;
- 更新页表项,设置有效位为 1;
- 重新执行指令:CPU 重新执行刚才触发缺页的指令,这次可以正常访问。
3.3 一个具体的例子
假设程序访问虚拟地址 0x00003A5C,页号为 0x00003。
- MMU 查页表,发现页号
0x00003的有效位为 0; - 触发缺页中断;
- 操作系统检查地址合法,查找空闲页框,比如页框
0x00012; - 从磁盘读取页
0x00003的数据; - 把数据放入页框
0x00012; - 更新页表项:页号
0x00003→ 页框0x00012,有效位 = 1; - 重新执行指令,这次 MMU 查到有效位为 1,正常访问。
#mermaid-svg-IF07RPvNpUD0c40g{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IF07RPvNpUD0c40g .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IF07RPvNpUD0c40g .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IF07RPvNpUD0c40g .error-icon{fill:#552222;}#mermaid-svg-IF07RPvNpUD0c40g .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IF07RPvNpUD0c40g .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IF07RPvNpUD0c40g .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IF07RPvNpUD0c40g .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IF07RPvNpUD0c40g .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IF07RPvNpUD0c40g .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IF07RPvNpUD0c40g .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IF07RPvNpUD0c40g .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IF07RPvNpUD0c40g .marker.cross{stroke:#333333;}#mermaid-svg-IF07RPvNpUD0c40g svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IF07RPvNpUD0c40g p{margin:0;}#mermaid-svg-IF07RPvNpUD0c40g .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IF07RPvNpUD0c40g .cluster-label text{fill:#333;}#mermaid-svg-IF07RPvNpUD0c40g .cluster-label span{color:#333;}#mermaid-svg-IF07RPvNpUD0c40g .cluster-label span p{background-color:transparent;}#mermaid-svg-IF07RPvNpUD0c40g .label text,#mermaid-svg-IF07RPvNpUD0c40g span{fill:#333;color:#333;}#mermaid-svg-IF07RPvNpUD0c40g .node rect,#mermaid-svg-IF07RPvNpUD0c40g .node circle,#mermaid-svg-IF07RPvNpUD0c40g .node ellipse,#mermaid-svg-IF07RPvNpUD0c40g .node polygon,#mermaid-svg-IF07RPvNpUD0c40g .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IF07RPvNpUD0c40g .rough-node .label text,#mermaid-svg-IF07RPvNpUD0c40g .node .label text,#mermaid-svg-IF07RPvNpUD0c40g .image-shape .label,#mermaid-svg-IF07RPvNpUD0c40g .icon-shape .label{text-anchor:middle;}#mermaid-svg-IF07RPvNpUD0c40g .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IF07RPvNpUD0c40g .rough-node .label,#mermaid-svg-IF07RPvNpUD0c40g .node .label,#mermaid-svg-IF07RPvNpUD0c40g .image-shape .label,#mermaid-svg-IF07RPvNpUD0c40g .icon-shape .label{text-align:center;}#mermaid-svg-IF07RPvNpUD0c40g .node.clickable{cursor:pointer;}#mermaid-svg-IF07RPvNpUD0c40g .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IF07RPvNpUD0c40g .arrowheadPath{fill:#333333;}#mermaid-svg-IF07RPvNpUD0c40g .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IF07RPvNpUD0c40g .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IF07RPvNpUD0c40g .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IF07RPvNpUD0c40g .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IF07RPvNpUD0c40g .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IF07RPvNpUD0c40g .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IF07RPvNpUD0c40g .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IF07RPvNpUD0c40g .cluster text{fill:#333;}#mermaid-svg-IF07RPvNpUD0c40g .cluster span{color:#333;}#mermaid-svg-IF07RPvNpUD0c40g div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IF07RPvNpUD0c40g .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IF07RPvNpUD0c40g rect.text{fill:none;stroke-width:0;}#mermaid-svg-IF07RPvNpUD0c40g .icon-shape,#mermaid-svg-IF07RPvNpUD0c40g .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IF07RPvNpUD0c40g .icon-shape p,#mermaid-svg-IF07RPvNpUD0c40g .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IF07RPvNpUD0c40g .icon-shape .label rect,#mermaid-svg-IF07RPvNpUD0c40g .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IF07RPvNpUD0c40g .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IF07RPvNpUD0c40g .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IF07RPvNpUD0c40g :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 虚拟地址 0x00003A5C
页号 0x00003
页表项有效位=0
缺页中断
加载页到页框 0x00012
更新页表
重新执行指令
正常访问
图 5:缺页中断处理的具体例子。
四、页面置换:没有空闲页框怎么办?
4.1 为什么需要页面置换?
如果物理内存已满,没有空闲页框,操作系统必须换出 某个页,腾出空间给新页。选择换出哪个页,就是页面置换算法要解决的问题。
页面置换算法将在下一篇详细讲解,这里先介绍基本概念。
4.2 页面置换的流程
物理内存 磁盘 页表 操作系统 物理内存 磁盘 页表 操作系统 #mermaid-svg-epyDZrWHPyRgdgY0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-epyDZrWHPyRgdgY0 .error-icon{fill:#552222;}#mermaid-svg-epyDZrWHPyRgdgY0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-epyDZrWHPyRgdgY0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-epyDZrWHPyRgdgY0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-epyDZrWHPyRgdgY0 .marker.cross{stroke:#333333;}#mermaid-svg-epyDZrWHPyRgdgY0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-epyDZrWHPyRgdgY0 p{margin:0;}#mermaid-svg-epyDZrWHPyRgdgY0 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-epyDZrWHPyRgdgY0 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-epyDZrWHPyRgdgY0 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-epyDZrWHPyRgdgY0 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-epyDZrWHPyRgdgY0 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-epyDZrWHPyRgdgY0 .sequenceNumber{fill:white;}#mermaid-svg-epyDZrWHPyRgdgY0 #sequencenumber{fill:#333;}#mermaid-svg-epyDZrWHPyRgdgY0 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-epyDZrWHPyRgdgY0 .messageText{fill:#333;stroke:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-epyDZrWHPyRgdgY0 .labelText,#mermaid-svg-epyDZrWHPyRgdgY0 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .loopText,#mermaid-svg-epyDZrWHPyRgdgY0 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-epyDZrWHPyRgdgY0 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-epyDZrWHPyRgdgY0 .noteText,#mermaid-svg-epyDZrWHPyRgdgY0 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-epyDZrWHPyRgdgY0 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-epyDZrWHPyRgdgY0 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-epyDZrWHPyRgdgY0 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-epyDZrWHPyRgdgY0 .actorPopupMenu{position:absolute;}#mermaid-svg-epyDZrWHPyRgdgY0 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-epyDZrWHPyRgdgY0 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-epyDZrWHPyRgdgY0 .actor-man circle,#mermaid-svg-epyDZrWHPyRgdgY0 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-epyDZrWHPyRgdgY0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt修改位为 1(脏页)修改位为 0(干净页) 需要加载新页没有空闲页框选择牺牲页检查牺牲页的修改位写回牺牲页写回完成直接丢弃标记牺牲页无效读取新页返回新页数据放入牺牲页的页框更新页表项
图 6:页面置换的流程。 如果牺牲页被修改过,需要先写回磁盘。
4.3 脏页与干净页
| 类型 | 修改位 | 处理方式 |
|---|---|---|
| 脏页 | 1 | 必须先写回磁盘,再换出 |
| 干净页 | 0 | 直接丢弃,不需要写回 |
脏页 (Dirty Page)是被修改过的页,内容与磁盘上的副本不一致,换出前必须写回磁盘。干净页(Clean Page)没有被修改,可以直接丢弃。
五、缺页中断的性能影响
5.1 缺页中断的开销
缺页中断的开销非常大,主要包括:
| 开销来源 | 说明 |
|---|---|
| 上下文切换 | 从用户态切换到内核态 |
| 地址检查 | 检查地址合法性 |
| 页面置换 | 选择牺牲页,可能写回磁盘 |
| 磁盘 I/O | 从磁盘读取页(最慢) |
| 页表更新 | 更新页表项 |
| TLB 刷新 | 使旧的 TLB 条目失效 |
| 重新执行 | 重新执行触发缺页的指令 |
其中,磁盘 I/O 是最大的开销。磁盘访问时间通常在几毫秒 级别,而内存访问时间在几十纳秒级别,相差 10 万倍。
#mermaid-svg-JGKk1k3f2JxKvmyi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JGKk1k3f2JxKvmyi .error-icon{fill:#552222;}#mermaid-svg-JGKk1k3f2JxKvmyi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JGKk1k3f2JxKvmyi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JGKk1k3f2JxKvmyi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JGKk1k3f2JxKvmyi .marker.cross{stroke:#333333;}#mermaid-svg-JGKk1k3f2JxKvmyi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JGKk1k3f2JxKvmyi p{margin:0;}#mermaid-svg-JGKk1k3f2JxKvmyi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi .cluster-label text{fill:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi .cluster-label span{color:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi .cluster-label span p{background-color:transparent;}#mermaid-svg-JGKk1k3f2JxKvmyi .label text,#mermaid-svg-JGKk1k3f2JxKvmyi span{fill:#333;color:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi .node rect,#mermaid-svg-JGKk1k3f2JxKvmyi .node circle,#mermaid-svg-JGKk1k3f2JxKvmyi .node ellipse,#mermaid-svg-JGKk1k3f2JxKvmyi .node polygon,#mermaid-svg-JGKk1k3f2JxKvmyi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JGKk1k3f2JxKvmyi .rough-node .label text,#mermaid-svg-JGKk1k3f2JxKvmyi .node .label text,#mermaid-svg-JGKk1k3f2JxKvmyi .image-shape .label,#mermaid-svg-JGKk1k3f2JxKvmyi .icon-shape .label{text-anchor:middle;}#mermaid-svg-JGKk1k3f2JxKvmyi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JGKk1k3f2JxKvmyi .rough-node .label,#mermaid-svg-JGKk1k3f2JxKvmyi .node .label,#mermaid-svg-JGKk1k3f2JxKvmyi .image-shape .label,#mermaid-svg-JGKk1k3f2JxKvmyi .icon-shape .label{text-align:center;}#mermaid-svg-JGKk1k3f2JxKvmyi .node.clickable{cursor:pointer;}#mermaid-svg-JGKk1k3f2JxKvmyi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JGKk1k3f2JxKvmyi .arrowheadPath{fill:#333333;}#mermaid-svg-JGKk1k3f2JxKvmyi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JGKk1k3f2JxKvmyi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JGKk1k3f2JxKvmyi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGKk1k3f2JxKvmyi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JGKk1k3f2JxKvmyi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGKk1k3f2JxKvmyi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JGKk1k3f2JxKvmyi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JGKk1k3f2JxKvmyi .cluster text{fill:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi .cluster span{color:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JGKk1k3f2JxKvmyi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JGKk1k3f2JxKvmyi rect.text{fill:none;stroke-width:0;}#mermaid-svg-JGKk1k3f2JxKvmyi .icon-shape,#mermaid-svg-JGKk1k3f2JxKvmyi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGKk1k3f2JxKvmyi .icon-shape p,#mermaid-svg-JGKk1k3f2JxKvmyi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JGKk1k3f2JxKvmyi .icon-shape .label rect,#mermaid-svg-JGKk1k3f2JxKvmyi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGKk1k3f2JxKvmyi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JGKk1k3f2JxKvmyi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JGKk1k3f2JxKvmyi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 几十纳秒
几毫秒
内存访问
完成
缺页中断
上下文切换
页面置换
磁盘 I/O
页表更新
重新执行
图 7:内存访问与缺页中断的开销对比。 缺页中断慢 10 万倍。
5.2 缺页率
缺页率(Page Fault Rate)是衡量虚拟内存性能的重要指标:
缺页率 = 缺页次数 / 总访问次数
缺页率越低,性能越好。理想情况下,缺页率应该低于 0.001%。
5.3 有效访问时间
有效访问时间(Effective Access Time,EAT)是考虑缺页中断后的平均访问时间:
EAT = (1 - p) × 内存访问时间 + p × 缺页处理时间
其中,p 是缺页率。
例如:
-
内存访问时间 = 100ns;
-
缺页处理时间 = 10ms = 10,000,000ns;
-
缺页率 = 0.001% = 0.00001。
EAT = (1 - 0.00001) × 100 + 0.00001 × 10,000,000
= 99.999 + 100
= 199.999ns
缺页率仅为 0.001% 时,有效访问时间就翻了一倍。
如果缺页率上升到 1%:
EAT = 0.99 × 100 + 0.01 × 10,000,000
= 99 + 100,000
= 100,099ns
性能下降 1000 倍。
#mermaid-svg-ilxkKFymQ2MZTZe7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ilxkKFymQ2MZTZe7 .error-icon{fill:#552222;}#mermaid-svg-ilxkKFymQ2MZTZe7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ilxkKFymQ2MZTZe7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .marker.cross{stroke:#333333;}#mermaid-svg-ilxkKFymQ2MZTZe7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ilxkKFymQ2MZTZe7 p{margin:0;}#mermaid-svg-ilxkKFymQ2MZTZe7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .cluster-label text{fill:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .cluster-label span{color:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .cluster-label span p{background-color:transparent;}#mermaid-svg-ilxkKFymQ2MZTZe7 .label text,#mermaid-svg-ilxkKFymQ2MZTZe7 span{fill:#333;color:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .node rect,#mermaid-svg-ilxkKFymQ2MZTZe7 .node circle,#mermaid-svg-ilxkKFymQ2MZTZe7 .node ellipse,#mermaid-svg-ilxkKFymQ2MZTZe7 .node polygon,#mermaid-svg-ilxkKFymQ2MZTZe7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .rough-node .label text,#mermaid-svg-ilxkKFymQ2MZTZe7 .node .label text,#mermaid-svg-ilxkKFymQ2MZTZe7 .image-shape .label,#mermaid-svg-ilxkKFymQ2MZTZe7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-ilxkKFymQ2MZTZe7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .rough-node .label,#mermaid-svg-ilxkKFymQ2MZTZe7 .node .label,#mermaid-svg-ilxkKFymQ2MZTZe7 .image-shape .label,#mermaid-svg-ilxkKFymQ2MZTZe7 .icon-shape .label{text-align:center;}#mermaid-svg-ilxkKFymQ2MZTZe7 .node.clickable{cursor:pointer;}#mermaid-svg-ilxkKFymQ2MZTZe7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .arrowheadPath{fill:#333333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ilxkKFymQ2MZTZe7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ilxkKFymQ2MZTZe7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ilxkKFymQ2MZTZe7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ilxkKFymQ2MZTZe7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .cluster text{fill:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 .cluster span{color:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ilxkKFymQ2MZTZe7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ilxkKFymQ2MZTZe7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-ilxkKFymQ2MZTZe7 .icon-shape,#mermaid-svg-ilxkKFymQ2MZTZe7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ilxkKFymQ2MZTZe7 .icon-shape p,#mermaid-svg-ilxkKFymQ2MZTZe7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ilxkKFymQ2MZTZe7 .icon-shape .label rect,#mermaid-svg-ilxkKFymQ2MZTZe7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ilxkKFymQ2MZTZe7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ilxkKFymQ2MZTZe7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ilxkKFymQ2MZTZe7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 缺页率对性能的影响
0.001%: 性能下降 2 倍
0.1%: 性能下降 100 倍
1%: 性能下降 1000 倍
图 8:缺页率对性能的巨大影响。
5.4 抖动
如果物理内存严重不足,系统会频繁换入换出,导致 CPU 大部分时间花在换页上,而不是执行程序。这种现象称为抖动(Thrashing)。
抖动的表现:
- CPU 利用率低;
- 磁盘 I/O 频繁;
- 系统响应极慢。
解决方案:
- 增加物理内存;
- 减少并发进程数;
- 使用更优的页面置换算法;
- 使用工作集模型,保证每个进程有足够的页框。
六、缺页中断的实际应用
6.1 Linux 中的缺页中断
Linux 的缺页中断处理程序在 arch/x86/mm/fault.c 中。处理流程包括:
- 检查地址是否合法;
- 判断是主缺页还是次缺页;
- 分配页框,从磁盘或交换空间读取页;
- 更新页表,重新执行指令。
bash
# 查看进程的缺页统计
ps -o min_flt,maj_flt -p PID
min_flt:次缺页次数(页在内存中,但页表未建立);maj_flt:主缺页次数(页不在内存中,需要磁盘 I/O)。
6.2 Windows 中的缺页中断
Windows 的缺页中断处理程序在 ntoskrnl.exe 中。Windows 使用工作集(Working Set)管理进程的内存页,确保活跃页留在内存中。
6.3 内存映射文件
内存映射文件(Memory-Mapped File)是缺页中断的典型应用。程序把文件映射到虚拟地址空间,访问文件就像访问内存一样。当程序访问未加载的页时,触发缺页中断,操作系统从文件读取对应页。
c
// 内存映射文件示例
void *addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
// 访问 addr 指向的内存,触发缺页中断自动加载
#mermaid-svg-I1LtarUKLX6KlpHr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-I1LtarUKLX6KlpHr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-I1LtarUKLX6KlpHr .error-icon{fill:#552222;}#mermaid-svg-I1LtarUKLX6KlpHr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-I1LtarUKLX6KlpHr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-I1LtarUKLX6KlpHr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-I1LtarUKLX6KlpHr .marker.cross{stroke:#333333;}#mermaid-svg-I1LtarUKLX6KlpHr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-I1LtarUKLX6KlpHr p{margin:0;}#mermaid-svg-I1LtarUKLX6KlpHr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-I1LtarUKLX6KlpHr .cluster-label text{fill:#333;}#mermaid-svg-I1LtarUKLX6KlpHr .cluster-label span{color:#333;}#mermaid-svg-I1LtarUKLX6KlpHr .cluster-label span p{background-color:transparent;}#mermaid-svg-I1LtarUKLX6KlpHr .label text,#mermaid-svg-I1LtarUKLX6KlpHr span{fill:#333;color:#333;}#mermaid-svg-I1LtarUKLX6KlpHr .node rect,#mermaid-svg-I1LtarUKLX6KlpHr .node circle,#mermaid-svg-I1LtarUKLX6KlpHr .node ellipse,#mermaid-svg-I1LtarUKLX6KlpHr .node polygon,#mermaid-svg-I1LtarUKLX6KlpHr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-I1LtarUKLX6KlpHr .rough-node .label text,#mermaid-svg-I1LtarUKLX6KlpHr .node .label text,#mermaid-svg-I1LtarUKLX6KlpHr .image-shape .label,#mermaid-svg-I1LtarUKLX6KlpHr .icon-shape .label{text-anchor:middle;}#mermaid-svg-I1LtarUKLX6KlpHr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-I1LtarUKLX6KlpHr .rough-node .label,#mermaid-svg-I1LtarUKLX6KlpHr .node .label,#mermaid-svg-I1LtarUKLX6KlpHr .image-shape .label,#mermaid-svg-I1LtarUKLX6KlpHr .icon-shape .label{text-align:center;}#mermaid-svg-I1LtarUKLX6KlpHr .node.clickable{cursor:pointer;}#mermaid-svg-I1LtarUKLX6KlpHr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-I1LtarUKLX6KlpHr .arrowheadPath{fill:#333333;}#mermaid-svg-I1LtarUKLX6KlpHr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-I1LtarUKLX6KlpHr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-I1LtarUKLX6KlpHr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I1LtarUKLX6KlpHr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-I1LtarUKLX6KlpHr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I1LtarUKLX6KlpHr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-I1LtarUKLX6KlpHr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-I1LtarUKLX6KlpHr .cluster text{fill:#333;}#mermaid-svg-I1LtarUKLX6KlpHr .cluster span{color:#333;}#mermaid-svg-I1LtarUKLX6KlpHr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-I1LtarUKLX6KlpHr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-I1LtarUKLX6KlpHr rect.text{fill:none;stroke-width:0;}#mermaid-svg-I1LtarUKLX6KlpHr .icon-shape,#mermaid-svg-I1LtarUKLX6KlpHr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I1LtarUKLX6KlpHr .icon-shape p,#mermaid-svg-I1LtarUKLX6KlpHr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-I1LtarUKLX6KlpHr .icon-shape .label rect,#mermaid-svg-I1LtarUKLX6KlpHr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I1LtarUKLX6KlpHr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-I1LtarUKLX6KlpHr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-I1LtarUKLX6KlpHr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 缺页中断应用
按需加载
内存映射文件
写时复制
交换空间
图 9:缺页中断的典型应用。
6.4 写时复制
写时复制(Copy-on-Write,COW)也依赖缺页中断。父进程创建子进程时,父子共享物理页,页表标记为只读。当任一进程写入时,触发缺页中断,操作系统复制该页,修改页表为可写。
6.5 交换空间
交换空间(Swap)是磁盘上的一块区域,用于存放被换出的页。当程序访问被换出的页时,触发缺页中断,操作系统从交换空间读回该页。
七、常见误区澄清
| 误区 | 真相 |
|---|---|
| "缺页中断就是错误" | 缺页中断是正常机制,不是错误 |
| "缺页中断一定需要磁盘 I/O" | 次缺页可能不需要磁盘 I/O |
| "缺页中断只发生在程序启动时" | 程序运行过程中随时可能发生 |
| "缺页率越低越好" | 缺页率低是好事,但完全消除不可能 |
| "增加内存就能消除缺页中断" | 增加内存能降低缺页率,但不能消除 |
| "缺页中断处理很快" | 缺页中断涉及磁盘 I/O,很慢 |
| "所有缺页中断都合法" | 访问非法地址会触发无效缺页,终止进程 |