1. MMU 基础概念:虚拟地址与物理地址的映射
各位同学,咱们今天聊聊 MMU。这东西在嵌入式 ARM 系统里,可以说是“兵家必争之地”。
很多刚入行的朋友觉得 MMU 就是个地址转换器,配置一下页表就完事了。嗯,我当年也这么想,直到在一个工控项目里,因为页表配置不当导致系统随机死机,排查了整整三天……从那以后,我对 MMU 的态度就变成了“敬畏”。
1.1 什么是 MMU?
MMU,全称 Memory Management Unit,内存管理单元。它是 CPU 内部的一个硬件模块,专门负责地址转换和内存保护。
说白了,它的核心工作就两件:
- 把虚拟地址变成物理地址
- 检查访问权限
你写的程序里用的地址,比如 0x10000,那叫虚拟地址。真正去内存里读写的地址,比如 0x80000000,那叫物理地址。MMU 就是这两者之间的“翻译官”。
核心概念:没有 MMU 的 CPU,程序直接操作物理地址。有 MMU 的 CPU,程序活在“虚拟世界”里,MMU 负责把虚拟世界映射到物理世界。
1.2 为什么需要 MMU?
你可能会问:直接操作物理地址不是更简单吗?为什么要多此一举?
我举个例子。在一个多任务系统里,进程 A 和进程 B 都要用地址 0x10000。如果没有 MMU,它们就会互相覆盖数据,系统直接崩溃。有了 MMU,每个进程看到的是自己的虚拟地址空间,互不干扰。
MMU 存在的几个关键理由:
| 需求 | 没有 MMU | 有 MMU |
|---|---|---|
| 进程隔离 | 进程可以随意访问任意物理内存 | 每个进程有独立虚拟空间,互不可见 |
| 内存保护 | 无法阻止非法访问 | 页表权限位控制读写执行 |
| 内存碎片 | 物理内存容易碎片化 | 虚拟地址连续,物理页可以分散 |
| 共享内存 | 实现复杂且不安全 | 不同虚拟地址映射到同一物理页 |
| 内存扩展 | 受限于物理内存大小 | 支持交换、按需分页 |
我的经验:在裸机或 RTOS 环境下,很多人会关掉 MMU 来省事。但一旦系统里跑多个任务,或者要跑 Linux,MMU 就是必须的。我曾经在一个项目里尝试在 RTOS 上关 MMU 跑 TCP/IP 协议栈,结果内存越界问题查得我怀疑人生……后来老老实实把 MMU 打开,问题迎刃而解。
1.3 虚拟地址与物理地址的映射关系
映射关系,就是页表里的一条条记录。每条记录告诉 MMU:虚拟地址 X 对应物理地址 Y,权限是什么。
ARM 处理器里,页表是多级结构的。以 ARMv7-A 为例,常用的是一级页表和二级页表:
- 一级页表(L1): 把 4GB 虚拟空间分成 4096 个 1MB 的段
- 二级页表(L2): 把每个 1MB 段再细分成 256 个 4KB 的页
为什么要多级?直接一张大表不行吗?
你想想看,4GB 空间如果用 4KB 页粒度,需要 1M 条页表项。每条 4 字节,就是 4MB。每个进程一张表,10 个进程就是 40MB。这还不算多,但很多嵌入式系统总共才 64MB 内存,光页表就吃掉一大半,不划算。
多级页表的好处是:按需分配。只给实际使用的虚拟地址范围分配页表,没用的区域不分配。
注意:页表层级越多,TLB miss 时的查表开销越大。ARM 的 TLB 会缓存最近使用的页表项,但如果你频繁切换进程或者访问大范围内存,TLB 命中率会下降。我在一个视频处理项目里就遇到过,因为页表配置不合理,TLB miss 率高达 30%,性能直接腰斩。
1.4 地址转换流程
一次典型的内存访问,MMU 干了这些事:
- CPU 发出虚拟地址
- MMU 检查 TLB 是否有对应项
- TLB 命中 → 直接得到物理地址
- TLB 未命中 → 硬件遍历页表
- 检查权限位(读/写/执行/特权级)
- 权限通过 → 生成物理地址,访问内存
- 权限不通过 → 触发异常(Segmentation Fault)
整个过程在几个时钟周期内完成。硬件自动完成,软件不需要干预——前提是你把页表配对了。
1.5 页表项结构
ARM 的页表项(PTE)包含几个关键字段:
| 字段 | 位数 | 说明 |
|---|---|---|
| 物理地址基址 | 20-24 位 | 映射到的物理页帧号 |
| 访问权限 | 2-3 位 | AP[2:0],控制读/写/特权 |
| 域 | 4 位 | ARM 特有的域访问控制 |
| 缓存属性 | 3 位 | C/B/TEX,控制 cache 策略 |
| XN | 1 位 | 禁止执行位,防止代码注入 |
| 脏位/访问位 | 2 位 | 用于页面置换算法 |
避坑指南:我曾经在配置页表时,把 AP 位写错了,导致用户态程序无法访问自己的数据段。查了半天发现是 AP[2] 设成了 0,强制所有访问都需要特权模式。嗯,这种低级错误,犯过一次就不会再犯了。
1.6 本章知识结构图
下面这张图展示了 MMU 的核心工作流程和页表层级关系:
1.7 小结
MMU 是嵌入式 ARM 系统的核心组件之一。它让每个进程拥有独立的虚拟地址空间,提供了内存保护和隔离,还支持按需分页和共享内存。
理解虚拟地址到物理地址的映射机制,是后续配置页表、优化 TLB 命中率、调试内存问题的前提。我个人觉得,这部分知识就像盖房子的地基——地基没打好,后面再漂亮的优化都是空中楼阁。
记住三个关键点:
- MMU 是硬件,页表是软件配置的数据结构
- 多级页表节省内存,但增加查表延迟
- TLB 是性能的关键,页表配置直接影响 TLB 命中率