前言
这是一个非常核心的计算机系统问题。现在来详细拆解一下80386内存管理中的分页机制是如何帮助程序运行的。
首先,要理解一个核心思想:分页机制为每个程序提供了一个独立的、连续的、从0开始的“虚拟”地址空间,并将这个空间映射到分散的、可能不连续的物理内存页上。
这就像一个酒店的经理,他手里只有一些分散的空房间(物理内存),但可以为每个旅行团(程序)分配一张连续的房号列表(虚拟地址空间),然后通过一个“房间分配表”(页表)将列表上的房号映射到真实的房间。
一. 分页机制的核心概念
1.1. 虚拟地址 vs. 物理地址
* 虚拟地址:程序看到的地址。它认为自己独占了整个4GB的地址空间(从0x00000000到0xFFFFFFFF)。这个地址是连续的。
* 物理地址:实际在内存条上的硬件地址。这些地址是离散的。
1.2. 页与页框
* 页:虚拟地址空间被划分为固定大小的块,称为“页”。在80386中,页的大小是4KB。
* 页框:物理内存也被划分为同样大小的块,称为“页框”。
* 分页的本质就是将“页”映射到“页框”。
1.3. 页表
* 这是一个数据结构,存储了虚拟页到物理页框的映射关系。
* 每一个进程都有自己独立的页表。
* 页表的每一项叫做“页表项”,它除了包含物理页框的基地址,还包含一些重要的控制位:
* P:存在位。为1表示该页当前在物理内存中;为0表示不在,访问它会引发缺页异常。
* R/W:读写位。为1表示可读可写;为0表示只读。
* U/S:用户/管理员位。决定用户态程序是否可以访问该页。
* A:访问位。被CPU访问后自动置1,用于页面替换算法。
* D:脏位。当页面被写入时自动置1,表示需要写回硬盘。
1.4. CR3寄存器
* 这是一个至关重要的CPU控制寄存器。它存储了当前正在运行的进程的页目录的物理基地址。
* 当操作系统进行任务切换时,它必须将新进程的页目录物理地址加载到CR3寄存器中。这就像给CPU换了一张新的总地图。
二. 地址转换过程:从虚拟地址到物理地址
80386使用两级页表来管理4GB的虚拟地址空间。这个过程完全由内存管理单元(MMU) 硬件自动完成,对程序是透明的。
一个32位的虚拟地址被划分为三部分:
| 31-22位 (10 bits) | 21-12位 (10 bits) | 11-0位 (12 bits) |
|---|---|---|
| 目录索引 | 页表索引 | 页内偏移 |
转换过程如下:
2.1. 从CR3寄存器找到页目录
* CR3寄存器指向当前进程的页目录。页目录也是一个4KB的页,包含1024个页目录项。
2.2. 使用目录索引找到页表
* 取虚拟地址的高10位(目录索引),乘以4(因为每个页目录项是4字节),得到在页目录中的偏移量。
* CPU通过 CR3 + 目录索引 * 4 找到对应的页目录项。这个PDE包含了第二级页表的物理基地址。
2.3. 使用页表索引找到物理页框
* 取虚拟地址的中间10位(页表索引),乘以4,得到在页表中的偏移量。
* CPU通过 页表物理基地址 + 页表索引 * 4 找到对应的页表项。这个PTE包含了目标物理页框的基地址。
2.4. 结合页内偏移得到最终物理地址
* 取虚拟地址的低12位(页内偏移)。
* 最终的物理地址 = 物理页框基地址 + 页内偏移。
整个过程可以总结为下图:
+-------------------+ +-----------------+ +-----------------+ +-----------------+
| 虚拟地址 (VA) | | 页目录 | | 页表 | | 物理内存 |
| 31 12 11 0 | | | | | | |
| [DIR][PAGE][OFFSET]| --> | PDE at (CR3+DIR)| --> | PTE at (PDE+PAGE)| --> | PA at (PTE+OFFSET)|
+-------------------+ +-----------------+ +-----------------+ +-----------------+
CPU生成 CR3指向 PDE指向 PTE指向
三. 分页机制如何运行程序:一个完整的场景
假设我们有一个程序app.exe,它要执行一条指令:mov eax, [0x00401000](读取虚拟地址0x00401000处的数据)。
3.1. 程序加载
* 操作系统创建进程,为它分配物理内存(页框),并建立其独立的页表。
* 将app.exe的代码段、数据段等内容加载到这些物理页框中,并在页表中建立映射(例如,将虚拟地址0x00401000映射到某个物理地址,比如0x12345000)。
* 操作系统将进程的页目录物理地址加载到CR3寄存器(在任务切换时)。
3.2. 指令执行与地址转换
* CPU执行mov eax, [0x00401000],需要访问虚拟地址0x00401000。
* MMU介入:
* 将0x00401000拆分为:目录索引=0x1,页表索引=0x1,偏移=0x000。
* 使用CR3找到页目录,用目录索引0x1找到页目录项,进而找到页表。
* 用页表索引0x1找到页表项,假设该PTE内容是0x12345000,且存在位P=1。
* MMU将物理页框基地址0x12345000与偏移0x000相加,得到物理地址0x12345000。
3.3. 内存访问
* CPU的内存控制器现在去访问物理地址0x12345000,将数据读取到寄存器eax中。
* 程序对此毫无感知,它以为自己访问的就是0x00401000。
四. 分页机制带来的关键好处
4.1. 进程隔离与保护:
* 每个进程有自己的页表,它们的虚拟地址空间是独立的。程序A无法访问程序B的内存,因为它的页表里根本没有程序B的物理页框映射。
* 通过R/W、U/S位,操作系统可以保护自己的内核代码不被用户程序修改或访问。
4.2. 提供连续的地址空间:
* 程序无需关心物理内存的碎片问题。它看到的是一个从0开始的、连续的4GB空间。
4.3. 实现虚拟内存:
* 交换:当物理内存不足时,操作系统可以将暂时不用的页“换出”到硬盘,并将其页表项的存在位P设为0,释放出物理页框。当程序再次访问这个页时,CPU会发现P=0,触发缺页异常。操作系统异常处理程序会负责从硬盘将该页“换入”内存,更新页表,然后让程序重新执行那条指令。
* 按需加载:程序启动时,并非所有代码和数据都需要立刻加载到内存。可以只加载必要的页,当访问到不在内存的页时,再通过缺页异常加载。这大大加快了程序启动速度。
五. 概述总结
80386的分页机制就像一个全能的“地址翻译官”和“内存调度员”。它通过页表这个精巧的数据结构,在程序发出的虚拟地址和硬件的物理地址之间建立了一层间接的映射。这个机制是多任务、内存保护和虚拟内存得以实现的硬件基础,是现代操作系统不可或缺的支柱。程序在分页机制的保护和帮助下,得以在一个安全、隔离、远大于实际物理内存的虚拟空间中流畅运行。
1234

被折叠的 条评论
为什么被折叠?



