3. 内存虚拟化概述
在 KVM 内存虚拟化中,最容易混淆的不是“有没有页表”,而是“到底有几层地址、每层地址由谁解释”。Guest 操作系统看到的是一套连续、从 0 开始的内存视图,但它实际占用的物理内存却由宿主机分配和管理。要理解 Stage-2 映射,必须先厘清三个核心地址概念:Guest 虚拟地址(GVA)、Guest 物理地址(GPA)和Host 物理地址(HPA)。它们分别对应 Guest 进程视角、Guest 内核视角和宿主机硬件视角。
一、三个地址空间:谁看见什么
Guest 虚拟地址是 Guest 内部进程使用的地址,由 Guest 自己的页表完成 GVA→GPA 的转换。Guest 物理地址是 Guest 内核眼中的“物理内存”,它并不等于真实内存条上的地址,而是 KVM 为虚拟机抽象出的一段地址空间。Host 物理地址才是真正落到宿主机 DRAM 上的地址。KVM 通过 Stage-2 页表把 GPA 映射到 HPA,从而让 Guest 的“物理内存”落在宿主机的真实内存页上。
可以用一个典型场景理解:Guest 中某进程访问 0x7f2a_1000(GVA),Guest 页表把它翻译成 GPA 0x1a000;KVM 的 Stage-2 页表再把 GPA 0x1a000 翻译成 HPA 0x3f8c_0000。最终 CPU 访问的是宿主机物理地址 0x3f8c_0000。整个过程对 Guest 完全透明,Guest 始终认为自己独占物理内存。
二、地址转换层次:两次翻译,一次访问
在传统操作系统中,一次内存访问只需一次页表翻译:虚拟地址→物理地址。而在 KVM 虚拟化环境中,Guest 的一次内存访问需要经过两次翻译:第一次由 Guest 页表完成 GVA→GPA,第二次由 KVM 的 Stage-2 页表完成 GPA→HPA。硬件通过 EPT(Intel)或 NPT(AMD)在 CPU 内部完成这两级翻译,避免每次访问都触发 VM-Exit。
如果没有硬件辅助,KVM 只能使用影子页表(Shadow Page Table):把 Guest 页表和 Stage-2 映射合并成一张直接 GVA→HPA 的页表,由 KVM 维护。这种方式实现复杂、同步开销大,且 Guest 页表更新时需要大量拦截。现代 KVM 默认使用 EPT/NPT,Guest 页表更新不再需要 VM-Exit,只有 Stage-2 页表缺页时才由 KVM 处理。
核心结论:GVA→GPA 由 Guest 负责,GPA→HPA 由 KVM 负责。Stage-2 映射是 KVM 内存虚拟化的核心机制,它决定了 Guest 物理内存最终落在宿主机的哪些物理页上。
三、内存虚拟化的目标与约束
内存虚拟化的目标可以归纳为四点:隔离性、透明性、高效性和可管理性。隔离性要求不同虚拟机的内存互不可见;透明性要求 Guest 无需修改即可运行;高效性要求地址转换不能带来过大性能损失;可管理性要求宿主机能够灵活分配、回收、迁移和超分内存。
| 目标 | 含义 | 实现手段 | 典型挑战 |
|---|---|---|---|
| 隔离性 | 各 VM 内存互不干扰 | Stage-2 页表独立映射 | 侧信道攻击 |
| 透明性 | Guest 无需感知虚拟化 | GPA 抽象 + 硬件两级翻译 | 特殊指令拦截 |
| 高效性 | 接近原生的访问性能 | EPT/NPT、TLB 合并 | TLB 压力增大 |
| 可管理性 | 支持超分、迁移、回收 | KVM 内存槽、脏页跟踪 | 内存超分导致换页 |
四、案例:一次 Guest 内存访问的完整路径
假设 Guest 中某进程读取变量 buf[0],其 GVA 为 0x7f2a_1000。CPU 首先查 Guest 页表,得到 GPA 0x1a000;随后查 Stage-2 页表,得到 HPA 0x3f8c_0000;最后从宿主机物理地址 0x3f8c_0000 读取数据。若 Stage-2 页表项不存在,CPU 触发 EPT Violation,KVM 捕获后分配宿主机物理页、建立映射,再重新执行指令。
GVA 0x7f2a_1000
│ Guest 页表
▼
GPA 0x1a000
│ Stage-2 页表(EPT/NPT)
▼
HPA 0x3f8c_0000
│ 硬件访问
▼
DRAM 数据
五、常见误区与复盘
- 误区一:GPA 就是 HPA。GPA 只是 Guest 眼中的物理地址,KVM 可以把它映射到任意 HPA,二者没有固定对应关系。
- 误区二:Guest 页表能直接控制 HPA。Guest 页表只能产生 GPA,最终 HPA 由 KVM 的 Stage-2 页表决定,Guest 无法绕过。
- 误区三:有了 EPT 就不需要影子页表。EPT 解决了 GPA→HPA 的硬件加速,但 Guest 页表仍由 Guest 自己维护,两者职责不同。
- 误区四:内存虚拟化只影响性能。它还直接影响隔离性、迁移能力和内存超分策略,是虚拟化安全与弹性的基础。
学习建议:理解本节时,始终问自己三个问题——这个地址是谁产生的?由谁翻译?最终落在哪里?把 GVA、GPA、HPA 三者的“产生者、翻译者、消费者”列清楚,Stage-2 映射的脉络就会非常清晰。
总结来说,KVM 内存虚拟化通过引入 GPA 这一中间地址层,把 Guest 的物理内存视图与宿主机真实内存解耦。Guest 负责 GVA→GPA,KVM 负责 GPA→HPA,硬件通过 EPT/NPT 加速两级翻译。理解这三层地址和两次翻译,是后续掌握 Stage-2 页表结构、缺页处理和内存超分机制的前提。