虚拟内存和物理内存之间的映射关系
操作系统里 虚拟内存和物理内存之间的映射关系涉及到 页 (page)、页框 (page frame) 和 页表 (page table) 这几个核心概念。
1. 基本概念
- 虚拟内存 (Virtual Memory)
每个进程看到的都是一个完整的大地址空间(比如 0x0000 ~ 0xFFFFFFFF),这是一种“假象”,不是真的物理内存。
操作系统通过硬件(MMU,内存管理单元)+ 数据结构(页表)把它映射到真正的物理内存上。 - 物理内存 (Physical Memory)
就是实际的 RAM 芯片,只有一份,大小有限。多个进程要共享使用。 - 页 (Page)
虚拟内存被分成等大小的小块(通常 4KB,一页)。
👉 页属于 虚拟地址空间。 - 页框 (Page Frame 或 Frame)
物理内存同样被分成等大小的小块(和页大小相同,比如 4KB,一页框)。
👉 页框属于 物理地址空间。 - 页表 (Page Table)
是一个映射表:记录“虚拟页号 → 物理页框号”的对应关系。
👉 页表存在于内存里,由操作系统管理,MMU 使用它来做地址转换。
2. 地址转换过程(虚拟地址 → 物理地址)
步骤:
-
CPU 发出一个虚拟地址 (Virtual Address)。
-
MMU 截获这个地址,将其拆解为 虚拟页号 (VPN) 和 页内偏移量 (Offset)。
- 例如,对于4KB的页,虚拟地址的低12位是偏移量,高位是页号。
-
MMU 去查询当前进程的页表。它使用 VPN 作为索引,去页表中找到对应的页表项 (PTE)。
-
页表项 (PTE) 中包含了最重要的信息:
- 有效位 (Valid Bit):最重要的一位。如果为
1
,表示该页已加载在物理内存中。如果为0
,则引发缺页异常 (Page Fault),需要操作系统介入(后面说)。 - 物理页框号 (PFN):如果有效位为
1
,这里就存储着这个虚拟页对应的物理页框号。 - 其他位:权限位(是否可读、可写、可执行)、访问位、修改位等。
- 有效位 (Valid Bit):最重要的一位。如果为
-
MMU 将得到的物理页框号 (PFN) 和原始的页内偏移量组合起来,就得到了最终的物理地址。
-
MMU 用这个物理地址去访问物理内存,完成读/写操作。
虚拟地址(VA) = 虚拟页号 (VPN) + 页内偏移量 (offset) 物理地址(PA) = 物理页框号(PFN) + 页内偏移量(offset) 偏移量不用变,因为一页大小一样。
-
📌 举个例子
- 假设虚拟地址空间:32 位,页大小 = 4KB (即 2¹² 字节)。
- 则:
- 虚拟地址 =
[VPN 20位] + [offset 12位]
- 页表是个数组,长度 = 2²⁰ ≈ 100 万个条目。
- 虚拟地址 =
- CPU 发出
VA = 0x12345678
:- VPN =
0x12345
,offset =0x678
- MMU 查页表[0x12345],找到 PTE:PFN =
0xABCD
- 物理地址 =
0xABCD678
- VPN =
3. 缺页 & 换入换出
- 如果某个虚拟页当前没有在物理内存里,页表会标记“缺页”。
- CPU 访问时触发 缺页异常 (Page Fault),OS 会把这个虚拟页从磁盘(swap 或文件)加载到某个空闲页框。
- 如果物理内存不够,就会挑一个旧的页框换出到磁盘(页面置换算法:FIFO、LRU 等)。
4. 总结一句话
- 页 (Page) 是虚拟内存的单位。
- 页框 (Page Frame) 是物理内存的单位。
- 页表 (Page Table) 负责把虚拟页号映射到物理页框号,从而让进程用虚拟地址就能访问到真实的物理内存。
虚拟内存和物理内存通过“页表”这个中间数据结构联系起来。页表存储了“虚拟页”到“物理页框”的映射关系。当程序使用虚拟地址访问内存时,CPU中的MMU硬件会自动查阅页表,找到对应的物理地址,从而访问到真正的物理内存。这个过程对应用程序是完全透明的。
为什么需要怎么复杂的机制?
!!!没错,这是一种机制 !连接“虚拟地址空间”和“物理内存”的一套机制。这套机制的核心组件就是页表和缺页处理。
- 进程隔离与保护:每个进程有自己的页表。进程A的虚拟页0映射到物理页框100,进程B的虚拟页0可能映射到物理页框200。它们彼此看不见对方的物理内存,无法互相篡改,非常安全。
- 提供连续的地址空间抽象:程序无需关心物理内存的碎片化。它觉得自己用的就是一整块从0到4GB的大内存,极大简化了编程。
- enabling 虚拟内存的魔法:这是最强大的一点。页表项中的有效位为
0
时,表示这个页不在物理内存中,可能被存到了磁盘上的交换空间 (Swap Space) 里。当程序访问它时,会触发缺页异常,操作系统会负责将这个页从磁盘加载到一个空闲的物理页框中,然后更新页表,最后再让程序重新执行那条指令。这使得程序可以使用比实际物理内存大得多的地址空间。
📌 举个例子看看进程隔离的具体实现:
- 进程A 和 进程B 都有自己的私有页表。
- 它们可以拥有相同的虚拟地址(例如都是
0x12345678
)。 - 但通过查询各自独立的页表,这个相同的虚拟地址会被翻译到不同的物理地址。
- 进程A 的页表将
VPN=0x12345
映射到PFN=0xABCD
-> 物理地址0xABCD678
- 进程B 的页表将
VPN=0x12345
映射到PFN=0xEF12
-> 物理地址0xEF12678
- 进程A 的页表将
这样,进程A和B对“同一个地址”的读写操作,实际上是在访问两块完全不同的物理内存,从而实现了完美的隔离和保护。一个进程根本无法通过虚拟地址访问到另一个进程的数据。
举个生动形象的类别帮助理解——🎓 大学图书馆与借书系统的类比
1. 物理内存 = 图书馆
- 图书馆就是 真实存在的物理内存。
- 它的空间有限,里面一格一格的书架就是 页框 (Page Frame)。
- 每个书架格子大小固定,比如 4KB,并且有唯一的物理位置编号(像“第3排,第5架,第2层”)。
2. 虚拟内存 = 借书目录
- 每个学生(进程)看到的都是一份属于自己的 完整借书目录,看起来好像图书馆无限大。
- 目录被切分成一条一条的条目(固定大小),这就是 页 (Page)。
- 这些页并不一定真的都在图书馆里,但在学生的感觉里,他随时能借到。
3. 页表 = 借阅登记簿
- 每个学生都有一本属于自己的 借阅登记簿 (页表)。
- 它记录了:
- 目录里的第N本书(虚拟页N) → 实际在哪个书架格子(物理页框X)。
- 可能标注“书还在仓库,未上架”(缺页)。
- 可能写着“无效,没权限借”(非法访问)。
示例:
- 虚拟页250 → 物理页框(3,5,2)
- 虚拟页101 → 缺页,需要从仓库取
- 虚拟页55 → 无效
4. MMU = 图书管理员
- MMU (内存管理单元) 就像专门的图书管理员。
- 学生(程序)说:“我要读目录里的地址0x4000”。
- 管理员自动:
- 在登记簿(页表)里查到:0x4000 属于虚拟页 1。
- 发现虚拟页 1 对应物理页框 1024。
- 于是转给图书馆:“去 1024 号格子里,取偏移X的数据”。
👉 这个过程叫 地址转换 (Address Translation),对学生完全透明。
在学生看来,他一直在操作一套从0开始、连续的内存(目录),但实际上背后是管理员在查登记簿、找真实格子。
5. 缺页 = 仓库调书
- 如果登记簿上写着“书还在仓库”,就发生 缺页异常 (Page Fault)。
- 管理员要去仓库(磁盘/Swap)把书搬到书架的一个格子里。
- 如果书架满了,就得把一本旧书放回仓库腾地方(页面置换算法)。
最后,重新讨论一下虚拟地址空间 (Virtual Address Space)、 虚拟内存 (Virtual Memory)和物理内存 (Physical Memory),放置概念混淆。
1.虚拟地址空间 (Virtual Address Space)
- 定义:每个进程独享的、巨大的、线性的地址范围。
- 你的例子:32位系统,地址范围是
0x00000000
~0xFFFFFFFF
,大小为 4 GB。 - 关键:进程认为自己独享整个4GB空间,这是一个“幻觉”。
- 物理内存 (Physical Memory)
- 定义:实际的RAM硬件,所有进程共享的宝贵资源。
- 大小:通常远小于4GB(如1GB),是真正存储数据和代码的地方。
- 虚拟内存 (Virtual Memory)
- 定义:连接“虚拟地址空间”和“物理内存”的一套机制。这套机制的核心组件就是页表和缺页处理。
- 目的:实现进程隔离、提供大于物理内存的空间、简化内存管理。