首页/计算机组成原理/存储器/虚拟存储器 🔗 在 Obsidian 中打开
计算机组成原理 · 存储器

虚拟存储器

重要度 ⭐⭐⭐⭐⭐存储器层次结构页式段式TLB页表地址转换存储器
速查
虚拟存储器用主存 + 外存构造更大的逻辑空间:虚地址 → TLB → 页表 → 实地址。TLB 命中最快(1 周期);页表缺失触发缺页异常(从磁盘调入)。页内偏移在转换前后不变

概述

虚拟存储器是利用主存和外存(磁盘)构建的逻辑上更大的存储空间。每个进程拥有独立的虚拟地址空间,通过地址转换映射到物理内存。它实现了内存保护共享自动管理

基本概念

虚拟地址(逻辑地址)

程序使用的地址,每个进程有自己的虚拟地址空间。

物理地址(实地址)

实际内存中的地址,所有进程共享物理地址空间。

地址转换

虚拟地址 → MMU(内存管理单元)→ 物理地址

页式虚拟存储器

基本原理

  • 虚拟地址空间划分为固定大小的页(Page)
  • 物理地址空间划分为同样大小的页框(Page Frame)
  • 页可以映射到任意页框

地址结构

虚拟地址 = [虚拟页号 VPN][页内偏移 Offset]
物理地址 = [物理页框号 PFN][页内偏移 Offset]

页内偏移位数 = log₂(页大小)
例:页大小 4KB → Offset = 12 位

页表(Page Table)

每个进程有一个页表:
虚拟页号 → [物理页框号, 有效位, 修改位, 访问权限...]

页表项(PTE)内容:
| 物理页框号 | V(有效位) | D(脏位) | R(访问位) | 权限 |

地址转换过程

1. 用虚拟页号查页表 → 得到页表项
2. 检查有效位:
   - 有效位 = 1 → 取物理页框号,拼接偏移得物理地址
   - 有效位 = 0 → 缺页异常(Page Fault)
3. 缺页处理:
   - 从磁盘调入页面到主存
   - 更新页表
   - 若主存满,需要页面置换
考点页内偏移在地址转换前后保持不变——只需把虚拟页号换成物理页框号。

多级页表

问题:单级页表太大(32 位地址 / 4KB 页 → 1M 个页表项)
解决:多级页表

二级页表:
虚拟地址 = [一级页号][二级页号][Offset]
第一级页表 → 指向第二级页表
第二级页表 → 指向物理页框
只加载需要的二级页表,节省空间

页表大小计算

32 位虚拟地址,4KB 页,4B 页表项:
页数 = 2^32 / 2^12 = 2^20 = 1M
页表大小 = 1M × 4B = 4MB(单级)

二级页表:
一级页表:2^10 × 4B = 4KB(刚好一页)
二级页表:每级 2^10 × 4B = 4KB(按需加载)

段式虚拟存储器

基本原理

  • 按程序逻辑结构分段(代码段、数据段、堆栈段等)
  • 每段大小可变;段内地址连续,段间可以不连续

地址结构

虚拟地址 = [段号][段内偏移]

段表(Segment Table)

段号 → [段基址, 段长, 访问权限...]

段表项内容:
| 段基址(Base) | 段长(Limit) | V(有效) | 权限 |

地址转换过程

1. 用段号查段表 → 得到段表项
2. 检查:段内偏移 < 段长?(越界检查)
3. 物理地址 = 段基址 + 段内偏移
特点优点:符合程序逻辑结构,便于共享和保护。缺点:段大小可变,内存管理复杂,产生外部碎片

段页式虚拟存储器

基本原理

先分段,再在段内分页,结合段式和页式的优点。

虚拟地址 = [段号][页号][页内偏移]

转换过程:
1. 查段表 → 得到页表基址
2. 查页表 → 得到物理页框号
3. 物理地址 = 物理页框号 + 页内偏移
特点有段的逻辑结构和保护,有页的固定大小和管理方便;需要两次查表(可用 TLB 加速)。

页式 vs 段式 vs 段页式

特性页式段式段页式
分割单位固定页可变段段内分页
碎片内部碎片外部碎片内部碎片
共享保护页级段级段级 + 页级
地址转换1 次查表1 次查表2 次查表
实现复杂度最高
实际应用Linux/Windows少用x86 架构

TLB(Translation Lookaside Buffer)

概念

  • TLB 是页表的高速缓存,存储最近使用的页表项
  • 通常全相联或组相联
| 虚拟页号 VPN | 物理页框号 PFN | 有效位 | ASID |

TLB 工作流程

1. CPU 发出虚拟地址
2. 用虚拟页号查 TLB
   - TLB 命中 → 直接得到物理页框号(1 个时钟周期)
   - TLB 未命中 → 查页表(可能多次访存)
3. 同时用物理页框号查 Cache
4. Cache 命中 → 取数据

TLB 与 Cache 的协作

组合代价
TLB 命中 + Cache 命中最快(1–2 个周期)
TLB 命中 + Cache 未命中访问主存
TLB 未命中 + Cache 命中先查页表(可能主存)
TLB 未命中 + Cache 未命中最慢

TLB 缺失处理

  • 硬件处理(CISC 风格):硬件自动查页表
  • 软件处理(RISC 风格):触发异常,操作系统处理
易混TLB 缺失不一定缺页:页可能还在内存中,只是 TLB 没缓存;TLB 用 ASID 区分不同进程的页表项。

页面置换算法

  • OPT(最优):替换未来最长时间不会被访问的页(不可实现,理论下界)
  • FIFO:替换最早进入内存的页
  • LRU:替换最近最久没有使用的页
  • 时钟算法(Clock):每页有访问位 R,指针循环扫描,$R=1$ 则清 0 继续,$R=0$ 则替换
  • 改进时钟算法:考虑修改位(脏页),优先替换未访问且未修改的页

缺页率与性能

有效访问时间 = 命中率 × (TLB时间 + Cache时间)
             + (1 − 命中率) × (页表访问时间 + Cache时间)
             + 缺页率 × 缺页处理时间
注意缺页率影响巨大:磁盘访问比主存慢约 10 万倍,一次缺页的代价足以抹掉成千上万次命中。

易错点

必记
  1. 页内偏移在地址转换前后不变
  2. TLB 缺失不一定缺页(页可能在内存中,只是 TLB 没缓存)。
  3. 缺页率影响巨大(磁盘访问比主存慢 10 万倍)。
  4. 多级页表节省空间但增加访问次数。
  5. 段页式需要先查段表再查页表,共两次查表。
  6. TLB 用 ASID 区分不同进程的页表项。
  7. 写操作需要检查页表项的写权限位

交互动画 · 地址转换流程

虚拟地址VPN | 偏移 TLB 快表命中 → PFN 页表VPN → PFN 磁盘(外存)调入页面 物理地址PFN | 偏移 主存取数据 虚地址 → TLB → 页表 → 物理地址;缺页时从磁盘调入
选择一种访问情形,观察地址转换的完整路径
点击上方按钮开始
示意图:橙色流动虚线表示当前激活路径;缺页异常走「页表 → 磁盘 → 页表 → 物理地址」的慢路径。

相关知识点

cache-mapping-methods virtual-memory virtual-memory-management

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。