Pentium处理器采用了分页的虚拟内存管理机制,其地址转换过程可以概括为“从虚拟地址到物理地址”的两级转换过程,这个过程由CPU的内存管理单元和操作系统共同协作完成。

核心概念:三种地址
在深入细节前,必须先理解三种地址的区别:
- 虚拟地址:由程序(CPU生成)使用的地址,它是一个逻辑地址,程序以为自己独占整个4GB的地址空间(在32位系统下),这是程序员和CPU日常打交道的地址。
- 线性地址:在x86架构中,虚拟地址经过分段机制转换后,会生成一个线性地址,在Pentium及以后的“平坦内存模型”(Flat Memory Model)下,虚拟地址和线性地址通常被认为是相同的,为了简化,我们后续将主要讨论从线性地址到物理地址的转换。
- 物理地址:内存芯片上的实际地址,数据真正存储在内存条上的位置。
我们的核心任务就是:虚拟地址 -> 物理地址
地址转换的硬件核心:分页机制
Pentium的分页机制将线性地址空间划分为固定大小的块,称为页,同样,物理内存也划分为同样大小的页框,转换的目标就是找到虚拟地址所在的“页”对应物理内存中的哪个“页框”。
页的大小
- Pentium处理器支持两种页大小:4KB 和 4MB(仅在Pentium Pro及更高型号中支持)。
- 我们主要分析最常见的4KB页。
页表的结构
页表是实现地址转换的“地图”,它是一个存放在物理内存中的数据结构,由操作系统创建和维护。

对于4KB的页,一个32位的线性地址被划分为三个部分:
| 31 - 22 | 21 - 12 | 11 - 0 |
|---|---|---|
| 页目录索引 | 页表索引 | 页内偏移 |
- 页内偏移:12位,表示在4KB页内的具体位置 (2^12 = 4096)。
- 页表索引:10位,用于在页表中查找对应的页表项。
- 页目录索引:10位,用于在页目录中查找对应的页目录项。
为什么是两级? 如果只用一个巨大的页表,它需要包含 2^20 (约100万个) 条目,占用4MB内存,非常浪费,使用两级结构,可以按需创建页表,节省内存。
地址转换的详细步骤
整个过程由CPU的MMU自动完成,但需要操作系统预先设置好数据结构。
步骤1:定位页目录
- CPU内部有一个特殊的寄存器,叫做页目录基址寄存器,它存储了页目录在物理内存中的起始地址。
- 这个寄存器是受特权级保护的,只有操作系统内核(运行在最高特权级Ring 0)才能修改。
步骤2:查页目录,找到页表的物理地址
- CPU取出线性地址的高10位(31-22位),作为页目录索引。
- 用这个索引去访问页目录,页目录本身就是一个数组,每个元素称为页目录项。
- CPU将页目录的基址寄存器中的地址,加上
索引 * 4(因为每个PDE是4字节),计算出PDE在内存中的地址。 - 从内存中读取这个PDE,PDE的结构如下:
| 31 - 12 | 11 - 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|---|---|
| 页表基址 | AVL | G | PAT | D | A | U/S | R/W | U/S | P | |
| (20位) |
- 最重要的字段是
P(Present) 位:P=0,表示该页表不在内存中,会触发一个缺页异常,操作系统需要介入处理。 - 最重要的字段是
页表基址:这是一个20位的物理地址,指向了页表的起始物理地址,CPU会将其扩展到32位(高位补零)。
步骤3:查页表,找到页框的物理地址
- CPU取出线性地址的中间10位(21-12位),作为页表索引。
- 用上一步找到的页表基址,加上
索引 * 4,计算出页表项在内存中的地址。 - 从内存中读取这个PTE,PTE的结构和PDE非常相似:
| 31 - 12 | 11 - 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|---|---|
| 页框基址 | AVL | G | PAT | D | A | U/S | R/W | U/S | P | |
| (20位) |
P(Present) 位:P=0,表示该页(即对应的代码或数据)不在内存中,触发缺页异常。页框基址:这是一个20位的物理地址,指向了页框的起始物理地址。
步骤4:组合成最终的物理地址
- CPU取出线性地址的低12位(11-0位),作为页内偏移。
- 将上一步找到的页框基址(20位)和页内偏移(12位)拼接起来。
- 物理地址 = 页框基址 + 页内偏移
CPU就得到了最终要访问的物理内存地址,并执行实际的内存读写操作。

TLB:转换后备缓冲区
上述过程需要访问内存两次(一次查页目录,一次查页表),这会严重影响性能,为了解决这个问题,CPU引入了TLB。
- 什么是TLB? TLB是一个位于CPU内部的小型、高速的缓存,专门用于存储最近使用的线性地址到物理地址的转换结果(即PTE的内容)。
- 工作流程:
- CPU在执行地址转换前,首先检查TLB。
- TLB命中:如果转换结果在TLB中,CPU直接从中获取物理地址,整个过程只需1-2个时钟周期,非常快。
- TLB未命中:如果转换结果不在TLB中,CPU才执行上面描述的、较慢的两次内存访问来查找页目录和页表,找到后,会将新的转换结果存入TLB,以便下次使用。
- TLB刷新:当操作系统修改了页表或页目录(一个进程被换出内存,它的页表被无效化),必须通知CPU刷新TLB中对应的条目,否则会使用错误的地址转换,这通过
INVLPG指令实现。
操作系统的角色
硬件提供了机制,但操作系统必须提供策略。
- 初始化:操作系统启动时,为自己创建一个初始的页目录和页表,并设置好CR3寄存器。
- 进程切换:当切换到另一个进程时,操作系统必须将该进程的页目录的物理地址加载到CR3寄存器中,这样,后续的地址转换就会使用新进程的“地址地图”。
- 缺页处理:当发生缺页异常时,操作系统会介入:
- 判断访问的内存页是合法的(即该进程的虚拟地址空间中确实有这个页)。
- 如果合法,但数据在硬盘的交换空间中,则从硬盘读取数据到内存的一个空闲页框中。
- 更新页表,将新的页框地址填入对应的PTE,并将P位置1。
- 返回到用户程序触发异常的指令处重新执行。
- 内存管理:操作系统负责跟踪哪些物理页框是空闲的,哪些已被占用,以及它们属于哪个进程。
4MB大页支持
Pentium Pro引入了对4MB大页的支持。
-
线性地址结构:线性地址只被分为两部分: | 31 - 22 | 21 - 0 | | :--- | :--- | | 页目录索引 | 页内偏移 |
-
转换过程:
- 用高10位索引查页目录,得到一个PDE。
- 这个PDE的
P位如果为1,并且一个特殊位(PS位,Page Size)为1,则表示这是一个4MB的大页。 - CPU不再使用页表,而是直接用PDE中的20位页框基址和低20位的页内偏移组合成最终的物理地址。
优点:只需要一次内存访问(查页目录),转换速度快,TLB命中率更高。 缺点:灵活性差,内存浪费可能更严重(因为一个页很大,如果只用到其中一小部分,其他部分就浪费了)。
Pentium处理器的地址转换是一个高效而复杂的硬件与软件协作的典范:
- 硬件层面:MMU通过两级页表(页目录->页表)结构,将32位线性地址高效地转换为32位物理地址。TLB作为高速缓存,极大地加速了转换过程。
- 软件层面:操作系统负责创建、维护和切换页表结构,并处理缺页异常等特殊情况,为每个进程提供独立的、受保护的虚拟地址空间。
这个设计不仅解决了内存不足的问题,还实现了进程间的内存隔离和内存保护,是现代多任务操作系统的基石。
