Linux 内存管理单元 MMU (下)
前言:在前面的文章Linux 内存管理单元 MMU(上)_linux 的mmu-CSDN博客中,我们介绍了MMU的一些基本知识,本文我们继续对多级页表、TLB及缺页异常机制做一些深入介绍。
目录
一、多级页表
在MMU上一篇文章中,我们介绍了分页机制及页表的概念。
简单回忆一下:MMU的“单位”是页。MMU 不是“一个字节一个字节”地翻译,而是“分页”。分页将虚拟地址空间划分为固定大小的块,称为页,常见的页大小为4KB,将物理内存划分为固定大小的块,称为页框。每个虚拟页通过页表映射到一个物理页框。
那什么是多级页表呢?为什么需要多级页表呢?
随着虚拟地址空间的增大,页表也会随之增大,会占用大量的内存。为了减少内存占用,节省资源并提高灵活性,Linux 采用多级页表结构。
多级页表的思想:
按需分配、稀疏存储,只分配实际使用的地址空间对应的页表,不需要的页表不必保留。它将原本巨大的单级页表拆解成多个小的页表,并通过一个顶层目录来管理它们。
以二级页表为例进行说明:
其结构包括:
- 页目录:这是顶层表,大小为一个页面(4KB)。它存储的是“页表”的物理地址。
- 页表:这是二级表,每个页表大小也是一个页面(4KB)。它存储的是实际的“物理页帧”地址。
在 32 位系统中,虚拟地址被分为三部分:页目录索引(10位) + 页表索引(10位) + 页内偏移(12位)。
地址转换过程如下:
- 第一步:CPU 根据寄存器(如 CR3)找到页目录的物理基地址。
- 第二步:使用虚拟地址的高 10 位作为索引,在页目录中查找,找到对应的页表物理地址。
- 第三步:使用虚拟地址的中间 10 位作为索引,在找到的页表中查找,找到最终的物理页帧地址。
- 第四步:将物理页帧地址与虚拟地址的低 12 位(页内偏移)拼接,得到最终的物理内存地址。
虚拟地址: [ 页目录索引 (10位) | 页表索引 (10位) | 页内偏移 (12位) ]
↓ ↓
[CR3寄存器指向] [页目录项指向]
↓ ↓
+-------------+ +-------------+
│ 页目录表 │ → │ 页表 │ → 物理页帧号
+-------------+ +-------------+
(1024项,4KB) (1024项,4KB)
二、TLB
多级页表极大地节省了内存空间,但,它也存在着一个显著的弊端: 访问速度变慢。
多级页表是采用时间换空间的方式,转换速度会明显降低,比如二级页表要得到最终物理地址,需要访问两次内存(先查页目录,再查页表)。
为了解决访问变慢的问题,现代 CPU 引入了 TLB(Translation Lookaside Buffer,转址旁路缓存)。
2.1 TLB概念
TLB 是一个高速缓存,其硬件设计类似于 CPU 的 L1 Cache。它专门存储最近使用的虚拟地址到物理地址的映射。绝大多数情况下,CPU 直接在 TLB 中就能找到地址,不需要去查多级页表,从而间接消除了多级页表带来的性能损耗。

2.2 TLB查找机制
TLB条目基本结构如下:
VPN(虚拟页号):用于匹配查找
PFN(物理页帧号):转换后的物理地址
权限位:访问权限控制
有效位:条目是否有效
其他标志:如脏位、全局位等
TLB的查找过程是一个并行比较的过程:
- 地址分解:将虚拟地址分解为 VPN(虚拟页号)和页内偏移
- 并行查找:硬件同时比较 TLB 中所有条目的标签(Tag)
- 匹配检查:如果找到匹配的 VPN,检查权限位和有效性
- 快速转换:TLB 命中时,直接获取物理页帧号(PFN),与页内偏移组合得到物理地址
三、缺页异常处理
3.1 缺页异常
当 CPU 试图访问一个虚拟地址,而该地址对应的物理页不在内存中(页表项中的存在位/Present Bit 为 0) 或者 访问权限不符的时候,这时候会触发缺页错误,暂停当前进程,跳转到操作系统内核预设的异常处理程序。
3.2 异常处理简要步骤
Step1:硬件触发
─ CPU访问虚拟地址,MMU发现页表项Present=0或访问权限不符
─ 自动保存故障地址到CR2寄存器,生成Error Code
─ 通过IDT向量14进入内核态
Step2:内核入口
─ 读取CR2获取故障地址,解析Error Code
Step3.:合法性检查
─ 查找VMA(虚拟内存区域)
─ 无VMA或权限不符 → 发送SIGSEGV,终止进程
─ 栈区域需扩展 → expand_stack()
Step4:分类处理
─ 匿名页首次访问 → 分配零页/新页
─ 文件映射缺页 → 从磁盘读入page cache
─ 页面在swap → 分配页帧,从交换区读回(I/O等待)
─ 写保护异常(COW)→ 复制页面或改权限
Step5:建立映射
─ 分配物理页(可能触发页面回收)
─ 构造页表项(Present=1,设置帧号和权限)
─ 原子写入页表
Step6:TLB刷新
─ INVLPG/TLBI指令使旧TLB项失效
Step7:返回恢复
─ 恢复现场,IRET返回用户态
─ 重新执行触发指令
更多推荐




所有评论(0)