深入浅出KVM内存管理——Ansible安全基线配置(一)
深入浅出KVM内存管理
引言
本文介绍了KVM的内存管理机制设计,用于帮助大家更深入理解KVM的内存管理
概括:KVM、QEMU 和 CPU 的“铁三角”
KVM (Kernel-based Virtual Machine) 本身是 Linux 内核的一个模块,它很“懒”——它自己不模拟硬件,而是利用 CPU 的硬件虚拟化扩展。它真正“干活”是和 QEMU 一起
你可以这样理解:QEMU 负责“模拟”一个完整的PC(主板、磁盘、网卡等),而 KVM 负责“插手”最关键的 CPU 和内存访问,把 QEMU 的模拟操作“抢过来”交给真实的硬件去执行
所以,KVM 的内存机制,本质上是 KVM-QEMU 联手,并深度依赖 CPU 硬件的一套精妙体系
我们详细拆解一下这个机制:
基本框架:Guest 内存 = QEMU 进程的内存
这是理解一切的起点
当你启动一个 KVM 虚拟机时,在你的 Host 主机上,你会看到一个 QEMU 进程(例如 qemu-system-x86_64)
你为虚拟机分配 8GB 内存,QEMU 进程就会在 Host 主机上申请 8GB 的虚拟内存(通过 mmap 系统调用,说人话就是内存映射)
- 从 Host 主机看来: 这 8GB 内存就是
QEMU进程的普通内存空间。它是受 Host 主机的 Linux 内核管理,可以被swap(交换)到磁盘,也可以被KSM合并(后面会讲) - 从 Guest 虚拟机看来: 这 8GB 的内存是它的“物理内存”
核心魔法:二级地址转换 (EPT / NPT)
Guest 虚拟机里的一个程序(比如 Nginx)要访问内存。它走的是:
- Guest 虚拟地址 (GVA): 程序用的地址。
- Guest 物理地址 (GPA): Guest 操作系统的内核把它转换成的“物理地址”
但是,CPU 真正要访问的是 Host 物理地址 (HPA)(你服务器内存条上的真实地址)
在没有硬件辅助的时代,虚拟机需要“捕获”Guest 的每一次内存访问,用软件模拟(比如“影子页表”),这非常非常慢。
现在,KVM 依赖 CPU 的二级地址转换(SLAT)技术来零开销完成这个转换:
- Intel 称之为:EPT (Extended Page Tables)
- AMD 称之为:NPT (Nested Page Tables) 或 RVI (Rapid Virtualization Indexing)
KVM 会为每个虚拟机维护一套 EPT/NPT 页表,这套页表直接告诉 CPU 如何将 GPA 映射到 HPA
整个流程是这样的:
当 Guest 里的程序访问内存时,CPU 会自动地、在硬件层面完成两次转换:
- GVA -> GPA:使用 Guest 自己的页表(由 Guest OS 维护,存在
CR3寄存器)- GPA -> HPA:使用 KVM 设置的 EPT/NPT 页表
整个过程一步到位,不需要 KVM 介入,没有 VM-Exit,几乎和裸金属一样快!
只有当 Guest 访问的 GPA 在 EPT/NPT 表里不存在(比如缺页)时,才会触发一次 VM-Exit,KVM 这才“醒来”处理,比如给它分配一块新的 Host 内存,并更新 EPT 表
高级内存特性
光有 EPT/NPT 还不够,为了让内存使用更高效、更灵活,KVM (QEMU) 还提供了一系列高级功能
1. 内存超售:KSM (Kernel Same-page Merging)
如果你在 Host 上开了 10 个一模一样的虚拟机,每个 4GB,难道你需要 40GB 物理内存吗?
不需要。这 10 个虚拟机的内存里,有大量页面是完全一样的(比如系统核心文件)
Host 上的 Linux 内核可以开启 KSM 功能。KSM 会在后台扫描所有 QEMU 进程的内存,如果发现两个或多个内容完全相同的内存页,它会:
- 合并它们,只在 Host 物理内存中保留一个副本
- 让所有原来指向不同副本的页表(EPT 表),都指向这个唯一的副本
- 将这个副本标记为写时复刻 (Copy-on-Write, COW)
当任何一个 VM 试图写入这个共享页面时,CPU 会触发保护异常,内核会立刻为这个 VM 复制一个新的私有页面副本,让它去写,而其他 VM 不受影响。这就是内存超售的主要技术之一
2. 动态内存:Virtio Balloon (内存气球)
如果一个 VM 启动时用了 8GB,但是现在只用了 2GB,而另一个 VM 内存又不够了,怎么办?
Virtio Balloon 登场。它主要包含两部分:
- Host 上的 QEMU: 管理“气球”的充/放气
- Guest 里的
virtio_balloon驱动: 必须在 VM 里安装这个驱动
回收内存(气球充气):
QEMU 通知 Guest 里的 virtio_balloon 驱动:“我需要 2GB 内存”。Guest 驱动收到后,就会向 Guest OS 申请 2GB 内存(作为一个普通程序去申请)。Guest OS 以为这个“气球”程序要用,就把它不常用的内存(比如 cache)分配给它。virtio_balloon 拿到这 2GB 内存的“物理地址 (GPA)”后,就告诉 Host:“这 2GB 你拿走吧,别让 Guest OS 碰它们了”。Host 随后就可以把这 2GB 对应的 HPA 分配给其他 VM
归还内存(气球放气):
反之,Host 释放对这 2GB 内存的占用,并通知 Guest 驱动:“你可以把那 2GB 还给你对应的 Guset OS 了”
3. 性能优化:Huge Pages (大页)
CPU 访问内存快,是因为有 TLB (Translation Lookaside Buffer) 这个高速缓存,它缓存了 GVA -> HPA 的映射关系
但是 TLB 的容量有限。如果都用 4KB 的小页面,一个 8GB 的 VM 需要 2,097,152 个页表项。TLB 根本存不下,就会造成 TLB Miss(说人话就是“缓存未命中”),CPU 就得去内存里重新查询页表(Page Walk),性能下降
Huge Pages(大页)允许使用 2MB 甚至 1GB 的大页面
对比:
- 4KB 小页: 8GB / 4KB = 2,097,152 个页表项 (TLB 存不下)
- 2MB 大页: 8GB / 2MB = 4,096 个页表项 (TLB 妥妥存下)
KVM/QEMU 可以配置使用 Host 上的“透明大页 (THP)”或“静态大页 (Hugetlbfs)”,极大地减少 TLB Miss,提升内存密集型应用的性能
4. NUMA 架构支持 (vNUMA)
在大型多 CPU 插槽的服务器上,内存是分布在不同 CPU 节点(Node)上的。CPU 访问”本地“内存(在自己的 Node 上)非常快,访问”远程“内存(在其他 CPU Node 上)就慢很多,这就是 NUMA
KVM/QEMU 支持 vNUMA,它可以把 Host 上的 NUMA 拓扑映射给 Guest
这样,Guest OS 也能”感知“到 NUMA 架构,它会智能地调度,尽量让运行在 vCPU 0 上的程序,去使用 vNode 0 上的内存。而 KVM 会确保 vCPU 0 真的跑在 CPU 0 上,vNode 0 的内存也真的分配在 Node 0 的物理内存上。这避免了昂贵的跨节点内存访问
影响KVM内存效率的因素
天下没有免费的午餐,虚拟化也会引入一些开销
1. 开销:EPT/NPT 页表本身的开销
- 体现: KVM 需要在 Host 的内存里为每一个 VM 维护一套
EPT/NPT页表(用来做GPA -> HPA映射)。这个页表本身也要占用内存。如果 VM 内存很大,这套页表也会不小 - 效率影响: 这是空间开销(Overhead)。你开了 VM,哪怕它啥也不干,这部分内存也必须被 KVM 占用
2. 开销:TLB Miss 的“加倍惩罚”
- 体现: 就像我们聊
TLB Miss时说的,一旦 Miss 了,CPU 必须去“漫游 (Page Walk)”页表 - 效率影响: 在 KVM 环境下,这个“漫游”更复杂!CPU 不仅要查 Guest 的页表(
GVA->GPA),还要查 KVM 的EPT表(GPA->HPA)。这个过程比裸金属更耗时,对 CPU L1/L2 缓存的压力也更大。
(这就是为什么“大页”在虚拟化中如此重要的原因,它用“空间”(2MB)换“时间”(TLB Miss 次数))
3. 开销:KSM 和 Balloon 的性能抖动
- 体现:
KSM在扫描内存时,会消耗 CPU- 当一个 VM 试图写入一个被
KSM共享的页面时,会触发“写时复制 (COW)”,这是一个VM-Exit,会造成一次轻微的性能抖动(Latency Spike) Balloon充气(回收内存)太猛,可能导致 Guest OS 开始错误地将内存Swap到磁盘,造成灾难性的“双重交换”(Guest 往虚拟磁盘写,Host 又把这个“磁盘文件”的数据换出到物理Swap)
- 效率影响: “省钱”(密度)的代价是牺牲了一点点 CPU 性能和潜在的延迟稳定性
总结:一个公寓比喻
- Host 主机: 公寓大楼的物业
- QEMU 进程: 一间公寓(一个 VM)
- Guest OS: 公寓的租户
- Guest "物理"内存 (GPA): 租户脑子里的“公寓平面图”(比如“我的卧室”、“我的客厅”)
- Host "物理"内存 (HPA): 物业持有的大楼真实设计图(比如“503室的卧室”在“大楼 5 楼 A 区”)
- EPT/NPT (SLAT): 一个超级翻译器。租户说“我要去卧室”,翻译器(CPU 硬件)瞬间查询 EPT 表,直接把租户“传送”到了“大楼 5 楼 A 区”
- KSM: 物业发现 A 户和 B 户都买了一模一样的宜家桌子,于是物业把两张桌子都收了,换成一张桌子放在公共区域,并告诉 A 和 B:“你们都来这用吧”。如果 A 要在桌上刻字(写入),物业立刻把桌子(
COW)复制一份新的给 A - Balloon: 物业(Host)想把 A 户的“客房”租给别人,于是派了个气球(
virtio_balloon驱动)进 A 户,把客房充(占)满。A 户(Guest OS)一看客房被占了,就没法用了。物业就把这个客房(内存)租给了 C 户
KVM 的内存机制就是这样一套结合了 QEMU 进程管理、CPU 硬件加速和 Linux 内核高级特性的复杂系统
- 点赞
- 收藏
- 关注作者
评论(0)