vault backup: 2026-06-13 23:46:22
This commit is contained in:
597
操作系统/14_分页存储管理/14_分页存储管理.md
Normal file
597
操作系统/14_分页存储管理/14_分页存储管理.md
Normal file
@@ -0,0 +1,597 @@
|
||||
# 14. 分页存储管理
|
||||
|
||||
> **课程**: 操作系统 - 存储器管理
|
||||
> **核心内容**: 碎片问题、分页思想、地址结构、页表、地址变换、TLB快表、多级页表、倒转页表
|
||||
|
||||
---
|
||||
|
||||
## 前置知识
|
||||
|
||||
- [[13_存储管理基础]] — 存储器层次结构、逻辑地址与物理地址、MMU
|
||||
- [[01_系统运行机制]] — CPU工作模式与硬件基础
|
||||
|
||||
---
|
||||
|
||||
## 一、碎片问题
|
||||
|
||||
在连续分配方式中,内存中会出现无法被利用的空闲区域,称为**碎片**。
|
||||
|
||||
| 碎片类型 | 出现位置 | 产生原因 | 对应分配方式 |
|
||||
|---------|---------|---------|------------|
|
||||
| **内碎片** (Internal Fragmentation) | 分配区域**内部** | 固定分区大小 > 进程实际需要 | 固定分区分配 |
|
||||
| **外碎片** (External Fragmentation) | 分配区域**外部** | 空闲分区太小,无法满足任何请求 | 动态分区分配 |
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph 内碎片示意
|
||||
direction TB
|
||||
A1["┌──────────────┐"]
|
||||
A2["│ 进程实际数据 │"]
|
||||
A3["│──────────────│"]
|
||||
A4["│ 未使用空间 │ ← 内碎片"]
|
||||
A5["└──────────────┘"]
|
||||
end
|
||||
|
||||
subgraph 外碎片示意
|
||||
direction TB
|
||||
B1["┌────┐ ┌────┐ ┌────┐ ┌────┐"]
|
||||
B2["│进程A│ │空闲│ │进程B│ │空闲│"]
|
||||
B3["└────┘ └────┘ └────┘ └────┘"]
|
||||
B4[" ↑外碎片 ↑外碎片"]
|
||||
end
|
||||
```
|
||||
|
||||
> **根本原因**: 无论是固定分区还是动态分区,都要求进程在内存中**连续存放**。要彻底解决碎片问题,必须放弃"连续"要求——这就是**分页**思想的核心出发点。
|
||||
|
||||
---
|
||||
|
||||
## 二、分页的基本思想
|
||||
|
||||
分页存储管理将**虚拟地址空间**和**物理内存**都划分为大小相等的小块:
|
||||
|
||||
- 虚拟地址空间的每一块称为**虚拟页 (Virtual Page, VP)**
|
||||
- 物理内存的每一块称为**物理页框 (Page Frame, PF)**
|
||||
|
||||
常见的页面大小为 $2^k$ 字节:512B、1KB、2KB、**4KB**(最常用)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph VA["虚拟地址空间 (进程视角)"]
|
||||
direction TB
|
||||
VP0["虚拟页 VP0"]
|
||||
VP1["虚拟页 VP1"]
|
||||
VP2["虚拟页 VP2"]
|
||||
VP3["虚拟页 VP3"]
|
||||
VP4["..."]
|
||||
end
|
||||
|
||||
subgraph PM["物理内存"]
|
||||
direction TB
|
||||
PF0["物理页框 PF0"]
|
||||
PF1["物理页框 PF1"]
|
||||
PF2["物理页框 PF2"]
|
||||
PF3["物理页框 PF3"]
|
||||
PF4["..."]
|
||||
end
|
||||
|
||||
VP0 -->|"页表映射"| PF2
|
||||
VP1 -->|"页表映射"| PF0
|
||||
VP2 -->|"不在内存"| DISK["外存(磁盘)"]
|
||||
VP3 -->|"页表映射"| PF3
|
||||
|
||||
style VA fill:#e3f2fd,stroke:#1976d2
|
||||
style PM fill:#fff8e1,stroke:#f9a825
|
||||
style DISK fill:#fce4ec,stroke:#c62828
|
||||
```
|
||||
|
||||
**关键特性**:
|
||||
- 虚拟页在物理内存中**不需要连续**存放
|
||||
- 每个虚拟页可以映射到任意一个空闲物理页框
|
||||
- 消除了外碎片(但每个页内可能有少量内碎片)
|
||||
|
||||
---
|
||||
|
||||
## 三、地址结构
|
||||
|
||||
在分页系统中,虚拟地址被划分为两部分:
|
||||
|
||||
```
|
||||
虚拟地址 VA (v+k 位)
|
||||
┌─────────────────┬─────────────┐
|
||||
│ VPN (v位) │ VPO (k位) │
|
||||
│ 虚拟页号 │ 页内偏移 │
|
||||
└─────────────────┴─────────────┘
|
||||
```
|
||||
|
||||
**计算公式**:
|
||||
- 页大小 = $2^k$ 字节
|
||||
- 虚拟页号 VPN = $\lfloor VA / 2^k \rfloor$(即高位部分)
|
||||
- 页内偏移 VPO = $VA \mod 2^k$(即低 $k$ 位)
|
||||
|
||||
物理地址同理:
|
||||
|
||||
```
|
||||
物理地址 PA (p+k 位)
|
||||
┌─────────────────┬─────────────┐
|
||||
│ PPN (p位) │ PPO (k位) │
|
||||
│ 物理页号 │ 页内偏移 │
|
||||
└─────────────────┴─────────────┘
|
||||
```
|
||||
|
||||
- 物理页号 PPN 由页表查得
|
||||
- **PPO = VPO**(页内偏移不变,直接复制)
|
||||
|
||||
### 地址计算示例
|
||||
|
||||
> **例题**: 某系统虚拟地址 16 位,页面大小 4KB ($2^{12}$),求虚拟地址 VA = 0x3A6F 对应的 VPN 和 VPO。
|
||||
|
||||
- 页大小 $2^k = 2^{12}$,所以 $k = 12$,$v = 16 - 12 = 4$
|
||||
- VPN = $0x3A6F / 0x1000 = 0x3$(高4位:0011)
|
||||
- VPO = $0x3A6F \mod 0x1000 = 0xA6F$(低12位)
|
||||
|
||||
```
|
||||
VA = 0x3A6F = 0011 1010 0110 1111
|
||||
──── ────────────────
|
||||
VPN VPO
|
||||
(0x3) (0xA6F)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、页表
|
||||
|
||||
页表是实现虚拟页到物理页框映射的核心数据结构。
|
||||
|
||||
### 页表结构
|
||||
|
||||
每个进程拥有**独立的页表**。页表以 VPN 为索引,每个页表项 (PTE) 包含:
|
||||
|
||||
```
|
||||
页表 (以VPN为索引)
|
||||
┌──────┬───────┬──────────────────────────────┐
|
||||
│ VPN │ PPN │ 控制位 │
|
||||
├──────┼───────┼──────────────────────────────┤
|
||||
│ 0 │ 5 │ V=1 D=0 R=1 W=1 U/S=1 │
|
||||
│ 1 │ 2 │ V=1 D=1 R=1 W=1 U/S=1 │
|
||||
│ 2 │ --- │ V=0 (不在内存) │
|
||||
│ 3 │ 8 │ V=1 D=0 R=1 W=0 U/S=1 │
|
||||
│ ... │ ... │ ... │
|
||||
└──────┴───────┴──────────────────────────────┘
|
||||
```
|
||||
|
||||
### 页表项 (PTE) 各字段
|
||||
|
||||
| 字段 | 含义 | 说明 |
|
||||
|------|------|------|
|
||||
| **有效位 (Valid/Present)** | 页面是否在内存中 | V=1:在内存;V=0:不在内存(缺页) |
|
||||
| **修改位 (Dirty)** | 页面是否被写过 | D=1:被修改过,换出时需写回外存 |
|
||||
| **引用位 (Reference)** | 页面是否被访问过 | 用于页面置换算法(如Clock、LRU近似) |
|
||||
| **读/写权限 (R/W)** | 读写保护 | 只读页被写入时触发保护异常 |
|
||||
| **用户/内核 (U/S)** | 访问权限 | U=0:仅内核可访问;U=1:用户可访问 |
|
||||
| **物理页号 (PPN)** | 对应的物理页框号 | 与VPO拼接得到物理地址 |
|
||||
|
||||
---
|
||||
|
||||
## 五、地址变换过程
|
||||
|
||||
### 基本地址变换流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["CPU发出虚拟地址 VA"] --> B["从VA中提取VPN和VPO"]
|
||||
B --> C{"TLB查找VPN"}
|
||||
C -->|"TLB命中"| D["直接取出PPN"]
|
||||
C -->|"TLB未命中"| E["访问页表<br/>(页表基址寄存器PTBR + VPN × PTE大小)"]
|
||||
E --> F{"页表项有效位?"}
|
||||
F -->|"V=1"| G["取出PPN"]
|
||||
F -->|"V=0"| H["**缺页中断**<br/>操作系统处理"]
|
||||
H --> I["从外存调入页面"]
|
||||
I --> J["更新页表"]
|
||||
J --> G
|
||||
D --> K["物理地址 PA = PPN × 2^k + PPO"]
|
||||
G --> K
|
||||
K --> L["访问物理内存"]
|
||||
|
||||
style H fill:#ffcdd2,stroke:#c62828
|
||||
style C fill:#e8f5e9,stroke:#2e7d32
|
||||
```
|
||||
|
||||
### 详细步骤
|
||||
|
||||
1. **提取地址字段**: 从虚拟地址 VA 中分离出 VPN 和 VPO
|
||||
2. **查TLB**: 用 VPN 在 TLB 中查找(见第六节)
|
||||
3. **查页表**: 若 TLB 未命中,用 **PTBR(页表基址寄存器)+ VPN** 定位页表项
|
||||
4. **检查有效位**:
|
||||
- V=1:取出 PPN,与 PPO 拼接得到物理地址
|
||||
- V=0:触发**缺页中断**,OS 从外存调入页面
|
||||
5. **拼接物理地址**: PA = PPN | PPO(将 PPN 放高位,PPO 放低位)
|
||||
|
||||
### 缺页中断处理流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["发生缺页中断"] --> B["保存CPU现场"]
|
||||
B --> C{"外存中找到该页?"}
|
||||
C -->|"找到"| D{"内存有空闲页框?"}
|
||||
C -->|"未找到"| E["终止进程<br/>(非法访问)"]
|
||||
D -->|"有空闲"| F["从外存读入该页"]
|
||||
D -->|"无空闲"| G["执行页面置换算法<br/>选择牺牲页"]
|
||||
G --> H{"牺牲页Dirty=1?"}
|
||||
H -->|"是"| I["将牺牲页写回外存"]
|
||||
H -->|"否"| J["直接覆盖"]
|
||||
I --> F
|
||||
J --> F
|
||||
F --> K["修改页表<br/>设置V=1, PPN"]
|
||||
K --> L["重新执行被中断的指令"]
|
||||
```
|
||||
|
||||
### 地址变换计算示例
|
||||
|
||||
> **例题**: 某系统页面大小 1KB ($2^{10}$),虚拟地址 14 位。页表如下,求虚拟地址 VA=0x1A8F 对应的物理地址。
|
||||
|
||||
| VPN | PPN | Valid |
|
||||
|-----|-----|-------|
|
||||
| 0 | 3 | 1 |
|
||||
| 1 | 7 | 1 |
|
||||
| 2 | --- | 0 |
|
||||
| 3 | 5 | 1 |
|
||||
| 4 | 2 | 1 |
|
||||
| 5 | 8 | 1 |
|
||||
| 6 | 1 | 1 |
|
||||
|
||||
**解题过程**:
|
||||
|
||||
1. 页面大小 $2^{10}$,所以 $k=10$,$v=14-10=4$
|
||||
2. VA = 0x1A8F = **01 1010 1000 1111** (二进制)
|
||||
- VPN = 高4位 = 0110 = **6**
|
||||
- VPO = 低10位 = 10 1000 1111 = 0x28F
|
||||
3. 查页表:VPN=6 对应 PPN=**1**,Valid=1
|
||||
4. PA = PPN | PPO = 1 × 2^{10} + 0x28F = 0x400 + 0x28F = **0x68F**
|
||||
|
||||
```
|
||||
VA = 0x1A8F: 0110 1010001111
|
||||
VPN=6 VPO=0x28F
|
||||
|
||||
查页表: VPN=6 → PPN=1
|
||||
|
||||
PA = 0001 1010001111 = 0x068F
|
||||
PPN=1 PPO=0x28F
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、TLB 快表
|
||||
|
||||
### TLB 概述
|
||||
|
||||
**TLB (Translation Lookaside Buffer)** 是集成在 MMU 中的高速缓存,存储最近使用的页表项。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
CPU["CPU"] -->|"虚拟地址"| TLB{"TLB<br/>(快表)"}
|
||||
TLB -->|"命中<br/>取出PPN"| PA["物理地址"]
|
||||
TLB -->|"未命中"| PT["查页表<br/>(内存)"]
|
||||
PT -->|"PPN"| PA
|
||||
PT -->|"更新TLB"| TLB
|
||||
|
||||
style TLB fill:#e8f5e9,stroke:#2e7d32
|
||||
style PT fill:#fff3e0,stroke:#e65100
|
||||
```
|
||||
|
||||
### TLB 组织方式
|
||||
|
||||
| 方式 | 说明 | 特点 |
|
||||
|------|------|------|
|
||||
| **全相联** | VPN可以放在TLB的任意位置 | 灵活但查找慢,适合小容量TLB |
|
||||
| **组相联** | VPN映射到固定的组(set),组内任意放置 | 折中方案,最常用 |
|
||||
| **直接映射** | VPN映射到固定的TLB位置 | 最快但冲突多 |
|
||||
|
||||
### TLB 性能分析
|
||||
|
||||
设 TLB 查找时间为 $\lambda$,内存访问时间为 $t$,TLB 命中率为 $a$:
|
||||
|
||||
**无 TLB 时**:每次地址变换需要访问一次页表(内存)+ 一次数据访问(内存)
|
||||
|
||||
$$EAT_{无TLB} = t + t = 2t$$
|
||||
|
||||
**有 TLB 时**:
|
||||
|
||||
$$EAT = a(\lambda + t) + (1-a)(\lambda + t + t) = \lambda + t + (1-a) \cdot t$$
|
||||
|
||||
> **计算示例**: 设 $\lambda = 10$ns, $t = 100$ns, $a = 0.98$(98%命中率)
|
||||
>
|
||||
> $EAT = 10 + 100 + (1 - 0.98) \times 100 = 10 + 100 + 2 = 112$ ns
|
||||
>
|
||||
> 相比无TLB的 $2t = 200$ ns,性能提升了约 **44%**。
|
||||
|
||||
---
|
||||
|
||||
## 七、多级页表
|
||||
|
||||
### 为什么需要多级页表
|
||||
|
||||
对于 32 位系统,页面大小 4KB:
|
||||
- 虚拟地址空间 = $2^{32}$ = 4GB
|
||||
- 页数 = $2^{32} / 2^{12} = 2^{20}$ = 1M 个页
|
||||
- 每个页表项 4 字节 → 页表大小 = 1M × 4B = **4MB**
|
||||
|
||||
4MB 的页表对于每个进程都太大了!而且页表必须连续存放。
|
||||
|
||||
### 二级页表结构
|
||||
|
||||
**核心思想**: 将页表本身也分页,用"页目录"来索引这些页表页。
|
||||
|
||||
```
|
||||
32位虚拟地址 (二级页表)
|
||||
┌──────────────┬──────────────┬──────────────┐
|
||||
│ 页目录索引(10位)│ 页表索引(10位) │ 页内偏移(12位)│
|
||||
└──────────────┴──────────────┴──────────────┘
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
CR3["CR3<br/>(页目录基址)"] --> PD["页目录<br/>(1024项)"]
|
||||
PD -->|"页目录项"| PT1["页表1<br/>(1024项)"]
|
||||
PD -->|"页目录项"| PT2["页表2<br/>(1024项)"]
|
||||
PD -->|"页目录项"| PT3["页表3<br/>(1024项)"]
|
||||
PT1 -->|"页表项+偏移"| PF1["物理页框"]
|
||||
PT2 -->|"页表项+偏移"| PF2["物理页框"]
|
||||
PT3 -->|"页表项+偏移"| PF3["物理页框"]
|
||||
|
||||
style PD fill:#e3f2fd,stroke:#1976d2
|
||||
style PT1 fill:#fff3e0,stroke:#e65100
|
||||
style PT2 fill:#fff3e0,stroke:#e65100
|
||||
style PT3 fill:#fff3e0,stroke:#e65100
|
||||
```
|
||||
|
||||
### 多级页表的优势
|
||||
|
||||
- 页目录只需常驻内存(4KB),页表页按需创建
|
||||
- 未使用的虚拟地址区域**不需要分配页表页**,节省大量内存
|
||||
- 64 位系统通常使用 **3~5 级页表**(如 Linux 的 4 级页表:PGD→PUD→PMD→PTE→偏移)
|
||||
|
||||
### 二级页表地址变换
|
||||
|
||||
1. 用 CR3 找到页目录基址
|
||||
2. 用**页目录索引**在页目录中找到页表页的物理地址
|
||||
3. 用**页表索引**在页表页中找到 PPN
|
||||
4. PPN 与**页内偏移**拼接得到物理地址
|
||||
|
||||
> **注意**: 二级页表需要 **3 次内存访问**(页目录 + 页表 + 数据),比一级页表多一次。因此 TLB 的作用更加重要。
|
||||
|
||||
---
|
||||
|
||||
## 八、倒转页表
|
||||
|
||||
### 基本思想
|
||||
|
||||
传统页表以**虚拟页号**为索引,每个进程一张。倒转页表以**物理页框号**为索引,整个系统一张。
|
||||
|
||||
| 对比项 | 传统页表 | 倒转页表 |
|
||||
|--------|---------|---------|
|
||||
| 索引 | 虚拟页号 (VPN) | 物理页框号 (PFN) |
|
||||
| 表项数 | 虚拟页数(可能很大) | 物理页框数(固定) |
|
||||
| 进程数 | 每进程一张 | 全系统一张 |
|
||||
| 查找方式 | 直接索引 | 需要搜索(或用Hash) |
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph 传统页表
|
||||
direction TB
|
||||
T1["VPN 0 → PPN x"]
|
||||
T2["VPN 1 → PPN y"]
|
||||
T3["VPN 2 → PPN z"]
|
||||
T4["..."]
|
||||
end
|
||||
|
||||
subgraph 倒转页表
|
||||
direction TB
|
||||
I1["PFN 0 ← VPN a, 进程P1"]
|
||||
I2["PFN 1 ← VPN b, 进程P2"]
|
||||
I3["PFN 2 ← VPN c, 进程P1"]
|
||||
I4["..."]
|
||||
end
|
||||
```
|
||||
|
||||
**优点**: 表大小与物理内存成正比,节省空间(尤其在 64 位系统)
|
||||
|
||||
**缺点**: 查找需要搜索整个表(通常用 Hash 加速)
|
||||
|
||||
---
|
||||
|
||||
## 九、内存保护
|
||||
|
||||
分页系统中通过以下机制实现内存保护:
|
||||
|
||||
### 1. 越界保护
|
||||
|
||||
- 页表项中的有效位 V=0 表示该页不在内存,访问时触发缺页中断
|
||||
- 非法虚拟地址(超出进程地址空间范围)触发保护异常
|
||||
|
||||
### 2. 标志位保护
|
||||
|
||||
| 标志位 | 保护功能 |
|
||||
|--------|---------|
|
||||
| R/W | 读/写权限控制。只读页被写入时触发异常 |
|
||||
| U/S | 用户/内核权限。用户态访问内核页时触发异常 |
|
||||
| NX (No Execute) | 禁止执行位。数据页被当作代码执行时触发异常 |
|
||||
|
||||
### 3. 键保护
|
||||
|
||||
- 每个物理页框有一个保护键 (Protection Key)
|
||||
- 每个进程有一个键寄存器
|
||||
- 只有键匹配时才允许访问
|
||||
- Intel MPX/MPK 技术支持此机制
|
||||
|
||||
---
|
||||
|
||||
## 十、空闲页面管理
|
||||
|
||||
操作系统需要跟踪物理内存中哪些页框是空闲的:
|
||||
|
||||
### 1. 位示图法 (Bitmap)
|
||||
|
||||
用一个 bit 表示一个物理页框的状态:0=空闲,1=已分配。
|
||||
|
||||
```
|
||||
位示图示例 (假设16个物理页框):
|
||||
位号: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
状态: 1 1 0 1 0 0 1 1 0 1 0 0 1 1 0 1
|
||||
↑ ↑ ↑
|
||||
空闲 空闲 空闲
|
||||
```
|
||||
|
||||
- **优点**: 简单,查找连续空闲块方便
|
||||
- **缺点**: 位示图本身占用内存(物理内存 4GB、页大小 4KB → 位示图 128KB)
|
||||
|
||||
### 2. 链表法
|
||||
|
||||
将所有空闲页框用链表串起来:
|
||||
|
||||
```
|
||||
空闲链表: [PF3] → [PF5] → [PF8] → [PF12] → NULL
|
||||
```
|
||||
|
||||
- **优点**: 实现简单,不额外占用大量空间
|
||||
- **缺点**: 查找连续空闲块需要遍历链表
|
||||
|
||||
---
|
||||
|
||||
## 十一、Nachos 页式存储管理代码
|
||||
|
||||
Nachos 教学操作系统中实现了基本的分页存储管理。以下是关键代码片段:
|
||||
|
||||
### 核心数据结构
|
||||
|
||||
```cpp
|
||||
// 页表项结构 (Machine/translate.h)
|
||||
typedef struct {
|
||||
int virtualPage; // 虚拟页号 (VPN)
|
||||
int physicalPage; // 物理页号 (PPN)
|
||||
bool valid; // 有效位
|
||||
bool readOnly; // 只读标志
|
||||
bool use; // 引用位 (用于LRU等算法)
|
||||
bool dirty; // 修改位
|
||||
} TranslationEntry;
|
||||
```
|
||||
|
||||
### 地址转换核心代码
|
||||
|
||||
```cpp
|
||||
// Machine/translate.cc - translate()
|
||||
// 将虚拟地址转换为物理地址
|
||||
int Machine::Translate(int virtAddr, int *physAddr, int size, bool writing) {
|
||||
// 1. 计算VPN和偏移
|
||||
int vpn = virtAddr / PageSize;
|
||||
int offset = virtAddr % PageSize;
|
||||
|
||||
// 2. 查找页表
|
||||
TranslationEntry *entry = &pageTable[vpn];
|
||||
|
||||
// 3. 检查有效位
|
||||
if (!entry->valid) {
|
||||
// 缺页处理
|
||||
return PageFaultException;
|
||||
}
|
||||
|
||||
// 4. 检查写权限
|
||||
if (writing && entry->readOnly) {
|
||||
return ReadOnlyException;
|
||||
}
|
||||
|
||||
// 5. 计算物理地址
|
||||
*physAddr = entry->physicalPage * PageSize + offset;
|
||||
|
||||
// 6. 更新引用位和修改位
|
||||
entry->use = true;
|
||||
if (writing) entry->dirty = true;
|
||||
|
||||
return NoException;
|
||||
}
|
||||
```
|
||||
|
||||
### 内存分配示例
|
||||
|
||||
```cpp
|
||||
// AddrSpace/addrspace.cc - 进程地址空间初始化
|
||||
// 为进程分配物理页框
|
||||
void AddrSpace::InitRegisters() {
|
||||
// 初始化页表
|
||||
pageTable = new TranslationEntry[numPages];
|
||||
for (int i = 0; i < numPages; i++) {
|
||||
pageTable[i].virtualPage = i;
|
||||
pageTable[i].physicalPage = bitMap->Find(); // 位示图分配
|
||||
pageTable[i].valid = true;
|
||||
pageTable[i].readOnly = false;
|
||||
pageTable[i].use = false;
|
||||
pageTable[i].dirty = false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、小结
|
||||
|
||||
```mermaid
|
||||
mindmap
|
||||
root((分页存储管理))
|
||||
碎片问题
|
||||
内碎片(固定分区)
|
||||
外碎片(动态分区)
|
||||
根因:连续存放
|
||||
分页思想
|
||||
虚拟页VP
|
||||
物理页框PF
|
||||
等大划分
|
||||
地址结构
|
||||
VPN+VPO
|
||||
PPN+PPO
|
||||
页内偏移不变
|
||||
页表
|
||||
VPN→PPN映射
|
||||
有效位/Dirty/Ref
|
||||
每进程独立
|
||||
地址变换
|
||||
PTBR+VPN查页表
|
||||
取PPN拼PPO
|
||||
缺页中断处理
|
||||
TLB快表
|
||||
高速缓存页表项
|
||||
命中率影响EAT
|
||||
多级页表
|
||||
页目录+页表
|
||||
节省内存
|
||||
倒转页表
|
||||
按物理块号索引
|
||||
全系统一张
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 思考题
|
||||
|
||||
1. **概念理解**: 为什么分页能消除外碎片但不能消除内碎片?内碎片平均浪费多少?
|
||||
|
||||
2. **计算题**: 某系统页面大小 4KB,虚拟地址 20 位,物理地址 18 位。
|
||||
- 虚拟地址空间有多少页?
|
||||
- 物理内存最大多少?
|
||||
- 页表至少需要多少项?
|
||||
|
||||
3. **TLB计算**: 设 TLB 查找时间 5ns,内存访问时间 80ns,要求有效访问时间不超过 100ns,TLB 命中率至少为多少?
|
||||
|
||||
4. **多级页表**: 对于 64 位系统,为什么至少需要 3 级页表?
|
||||
|
||||
---
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[13_存储管理基础]] — 存储器层次结构与地址空间基础
|
||||
- [[15_段式存储管理]] — 分段式地址转换,段页式结合
|
||||
- [[16_虚拟存储器]] — 基于分页的虚拟存储器实现
|
||||
- [[11_处理机调度]] — 进程调度与缺页处理的关系
|
||||
|
||||
---
|
||||
|
||||
**上一讲**: [[13_存储管理基础]]
|
||||
**下一讲**: [[15_段式存储管理]]
|
||||
Reference in New Issue
Block a user