更新记录(仅首版,2026年08月22日 发布)
- 首次发布
引用本文(DOI(已登记存档): 10.5281/zenodo.22176921)
以下 DOI 指向先前登记的存档,内容可能与当前正文不同。引用当前正文时,请使用本页网址。
Go Komura(2026)。《Windows 虚拟化的深层(第3回) ── 数秒即可启动的虚拟机:WSL2、Windows Sandbox 与容器为何这么轻》。小村软件有限公司。 https://comcomponent.com/zh-CN/blog/windows-virtualization-internals-wsl2-sandbox-containers/
- DOI(已登记存档)
- 10.5281/zenodo.22176921
- DOI(上次登记版本)
- 10.5281/zenodo.22176922
完整虚拟机那么重,WSL2 和 Windows Sandbox 为什么这么轻? 系列最终回不只从「隔离什么」,还要从「什么可以不复制」来解释这个差别。
在 Hyper-V 管理器里创建一台 Windows 虚拟机,启动要花几十秒,还会独占数 GB 内存。而在同一台 PC 上输入 wsl,几秒之内 Linux 外壳就会返回;Windows Sandbox 也在几秒内打开一个用完即弃的桌面。1
它们的地基都是第1回看到的 Windows 虚拟机监控程序。第2回确认了:用这层地基可以造出比内核更强的隔离。本文则分开来看 WSL2 的用途特化、Sandbox 的共享、容器的隔离模式。
「Windows 虚拟化的深层」全 3 回
同一套 Windows 虚拟机监控程序,按 地基 → 安全隔离 → 轻量虚拟机的应用 的顺序来看。
| 回 | 核心问题 |
|---|---|
| 第1回:虚拟机监控程序与分区 | 宿主的 Windows 到底在哪里运行 |
| 第2回:VBS、HVCI 与 Credential Guard | 连内核都读不到的秘密该放在哪里 |
| 第3回:WSL2、Windows Sandbox 与容器(本文) | 隔离原样保留,为什么还能这么轻 |
本文的前提
| 项目 | 内容 |
|---|---|
| 目标读者 | 想弄清 WSL2、Windows Sandbox 与 Windows 容器为何轻、又有哪些约束的开发者与运维人员 |
| 前提环境 | Windows 10/11。演示 Sandbox 需要 Pro、Enterprise、Education 之一,Home 和 Windows Server 没有这个功能 |
| 前提知识 | 第1回讲的分区概念 |
| 难度 | 中级 |
本文的读法
| 想了解的内容 | 该读的章节 |
|---|---|
| 完整虚拟机与轻量虚拟机到底差在哪里 | 第2节的比较基准 → 第3节的 WSL2 → 第4节的 Sandbox |
| 想理解 WSL2 的文件 I/O 与内存占用 | 第3.2节的文件放置 → 第3.3节的内存 |
| 想判断容器的安全性与选用场合 | 第5节的隔离模式 → 第7节的误读与注意事项 |
| 想在自己的环境里观察差异 | 第6节的确认方法 |
1. 先说结论
轻量虚拟机保住了隔离线(专用内核、虚拟机监控程序边界),只把「整套客户机操作系统的副本」减掉了。Sandbox 直接共享主机的 Windows 本身,WSL2 把客户机换成用途特化的小型 Linux,而两者的内存都不是固定预留,而是与主机动态调剂。
完整虚拟机之所以重,源头不是隔离本身,而是复制:磁盘上再放一份操作系统映像,内存里再占一份操作系统页面,每次启动再走一遍完整引导。轻量虚拟机用两条方针削掉这些复制——「能安全共享的就共享」(Sandbox),「不能共享就重新做小」(WSL2)。
flowchart TB
accTitle: 支撑轻量虚拟机的三种共享
accDescr: 完整虚拟机原本复制的操作系统映像,在 Sandbox 上改为共享、在 WSL2 上改为小型化;以固定分配为主(动态内存配置属于例外)的内存改为与主机动态调剂;启动改为轻量内核与最小配置,最后只留下隔离的边界
heavy["完整虚拟机之所以重,源头是复制"] --> d1["磁盘:复制一份操作系统映像"]
heavy --> d2["内存:以固定分配为主"]
heavy --> d3["启动:从头再走一遍完整引导"]
d1 -->|替换为| s1["共享(Sandbox)或小型化(WSL2)"]
d2 -->|替换为| s2["与主机动态借还"]
d3 -->|替换为| s3["用轻量内核与最小配置缩短"]
图1:放弃的不是隔离而是复制,这就是「同一套虚拟机监控程序却更轻」的答案骨架。
下面按 WSL2、Windows Sandbox、容器的顺序,看它们各自削掉了哪一份复制。
图中实线表示始终成立的关系,虚线表示带条件的关系(成立条件写在详情页各关系的说明中)。关系的完整列表(共 19 条,附依据与确信度)以及主要概念的定义,汇总在知识地图详情页(日文)。数据:JSON-LD / Turtle
2. 完整虚拟机背着哪些包袱
作为比较的基准,先整理一下传统虚拟机都背着什么。
- 独立的操作系统映像。 虚拟磁盘里装着客户机操作系统的全部文件。即便主机上有同一个 Windows 也不共享。
- 粗粒度的内存分配。 传统虚拟机基本上按静态大小从主机内存里划走。虽然也有像 Hyper-V 动态内存那样能在设定范围内增减分配量的机制,但随需求变化调整的手段仍然有限。2
- 通用的完整引导。 固件、引导加载程序、各种服务,都按与物理机相同的步骤启动。
flowchart TB
accTitle: 完整虚拟机背着的三件行李
accDescr: 完整虚拟机背着独立的操作系统映像、以静态为主的内存分配和通用的完整引导,这些最终表现为磁盘、RAM 与启动时间上的成本
fullvm["完整虚拟机"] --> b1["独立的操作系统映像"]
fullvm --> b2["以静态为主的内存分配"]
fullvm --> b3["通用的完整引导"]
b1 -.-> c1["磁盘要为这份副本再花一份"]
b2 -.-> c2["用不到的部分也占着 RAM"]
b3 -.-> c3["启动要几十秒"]
图2:完整虚拟机的成本明细,没有一项是为隔离付的,全都是为通用性和复制付的。
这些不是缺点,而是「客户机里想装什么都行」这份通用性的代价。在 Windows Server 旁边跑一个老版本 Linux 之类的场合,通用性本身就是价值。但如果目的是「把与主机相同(或指定)的操作系统,为开发和验证马上跑起来」,它们大多就成了多余的行李。轻量虚拟机通过收窄用途,把这些行李卸了下来。
3. WSL2 ── 装着用途特化内核的实用虚拟机
WSL2 按 结构 → 文件放在哪一侧 → 内存的归还 的顺序读会更清楚。「用的是真正的 Linux 内核」和「能高速处理 Windows 侧的文件」是两码事。
3.1. 结构:被管理的虚拟机,以及其中的发行版
WSL2 是在轻量实用虚拟机中运行真正 Linux 内核的机制。3 要点有三个。
内核是真的,只是做过特化
它是 Microsoft 从 Stable 分支构建的 Linux 内核,大小与性能都按 WSL2 调过。在当前标准的 Microsoft Store 分发版 WSL 中,内核与 WSL 本体的包一起更新,用 wsl --update 应用(Windows 内置的旧分发方式则经由 Windows Update)。4
因为是真正的内核,系统调用兼容性是完整的,Docker 这类工具也能直接跑起来。
虚拟机是幕后角色
虚拟机的创建、启动、停止都由 WSL 管理,使用者只要打开外壳即可。既没有虚拟机设置界面,也感觉不到启动等待。4
发行版是虚拟机内的容器
Ubuntu、Debian 等各个发行版,都作为隔离的容器运行在同一台被管理的虚拟机中。它们共享网络命名空间和内核,而 PID、挂载、用户等命名空间是分开的。3
flowchart TB
accTitle: WSL2 的架构
accDescr: 虚拟机监控程序之上并排着宿主 Windows 和轻量实用虚拟机,虚拟机中运行 Microsoft 构建的 Linux 内核,各个发行版作为其中隔离的容器运行
hv["虚拟机监控程序"] --> host["宿主 Windows"]
hv --> uvm["轻量实用虚拟机"]
uvm --> lk["Linux 内核(Microsoft 构建,用 wsl --update 更新)"]
lk --> u1["Ubuntu(容器)"]
lk --> u2["Debian(容器)"]
host <-->|"互操作(命令、文件、网络)"| uvm
图3:「WSL2 是不是虚拟机」的答案是「是,但是一台被管理的幕后虚拟机」;即使装多个发行版,虚拟机也只有一台。
输入 wsl 的那一瞬间,背后是这样的。
flowchart TB
accTitle: 从执行 wsl 命令到几秒后外壳返回
accDescr: 执行 wsl 时如果实用虚拟机尚未启动就启动轻量虚拟机和 Linux 内核,已启动则直接沿用,最后在发行版的容器里返回外壳
cmd["执行 wsl"] --> vmq{"实用虚拟机已启动?"}
vmq -->|否| bootvm["启动轻量虚拟机与 Linux 内核(数秒)"]
vmq -->|是| reuse["直接沿用已启动的虚拟机"]
bootvm --> shell["在容器内返回外壳"]
reuse --> shell
图4:等待时间的真身只是一次最小限度的虚拟机启动,卸掉完整引导这份行李的效果就体现在这里。
3.2. 文件 I/O:放在哪一侧,是两种完全不同的东西
谈 WSL2 性能时必定出现的话题,就是文件放在哪里。
- 对 Linux 侧(ext4 虚拟磁盘)的文件 的操作很快。因为 Linux 内核直接处理自己的文件系统;有报告称解压 tarball 比 WSL1 快最多 20 倍,
git clone和npm install快 2~5 倍。4 - 对 Windows 侧(/mnt/c 等)的文件 的操作要经过跨越操作系统边界的文件共享,因此会变慢。跨操作系统文件系统的性能,是 WSL2 唯一逊于 WSL1 的主要项目。4
所以原则是:「项目文件要放在操作它的工具所在的那一侧操作系统」。4 用 Linux 构建工具处理的仓库放在 Linux 侧,用 Visual Studio 构建的解决方案放在 Windows 侧。
flowchart TB
accTitle: WSL2 文件 I/O 路径的分岔
accDescr: 访问 Linux 侧的 ext4 虚拟磁盘时由 Linux 内核直接处理因而很快,访问 Windows 侧的文件则要经过跨越操作系统边界的文件共享因而较慢,这就是分岔所在
io["WSL2 内的文件操作"] --> place{"文件在哪一侧?"}
place -->|"Linux 侧(主目录等)"| ext4["直接对 ext4 虚拟磁盘做 I/O"]
place -->|"Windows 侧(/mnt/c 等)"| p9["经由跨越操作系统边界的共享"]
ext4 --> fast["快(有比 WSL1 快最多 20 倍的例子)"]
p9 --> slow["容易变慢"]
slow -.-> fix["对策:把文件放到使用它的那一侧操作系统"]
图5:慢的不是 WSL2 而是路径,所以很多时候只要换个放置位置,性能问题就消失了。
3.3. 内存:会涨,会落,但不会全还回去
WSL2 的内存占用(在任务管理器里显示为 vmmem 进程)不是固定预留,而是随使用量增减。
进程释放的内存如何归还
进程释放的内存,会在默认启用的 pageReporting 设置下自动还给 Windows。5
文件缓存的回收
作为文件缓存保留下来的页面,过去在虚拟机退出前不会还给 Windows。4 在现行的 WSL 中,.wslconfig 的实验性设置 autoMemoryReclaim(默认是 dropCache)会把缓存也自动回收。5
如果把这个设置改成 disabled,或者用的是旧版 WSL,长时间会话的缓存就会一直留到虚拟机退出,从而挤压主机侧的内存。
flowchart TB
accTitle: WSL2 内存的增减与归还流程
accDescr: WSL2 内需求上升会让虚拟机的内存占用增加,进程释放的部分在默认启用的 pageReporting 下还给 Windows,文件缓存默认由 autoMemoryReclaim 自动回收,但在关闭这些设置或旧版 WSL 上会一直留到虚拟机退出,用 wsl 的 shutdown 才全部归还
grow["WSL2 内的内存需求上升"] --> vm["vmmem 的占用量增加"]
vm --> freed{"那些页面被释放了吗?"}
freed -->|"进程已释放(pageReporting 启用时)"| ret["自动还给 Windows"]
freed -->|作为文件缓存保留| amr["autoMemoryReclaim 自动回收(默认)"]
amr -.-> old2["关闭设置或旧版 WSL 上会留到虚拟机退出"]
old2 --> sd["用 wsl --shutdown 全部归还"]
图6:看上去「只涨不落」的主要是缓存那部分(关闭 pageReporting 时进程释放的部分也会留着),所以在断定是泄漏之前,先了解归还的路径。
设定内存上限
想明确上限时,可以用 %UserProfile%\.wslconfig 控制整台虚拟机的内存、CPU 数与交换空间。5
# %UserProfile%\.wslconfig
[wsl2]
memory=8GB
processors=4
swap=2GB
改完设置后用 wsl --shutdown 重启虚拟机即可生效。这种「上限由配置决定,实际用量随需求而定」的动态分配,在接下来的 Windows Sandbox 上被贯彻得更彻底。
4. Windows Sandbox ── 把主机的 Windows「再用一次」
Sandbox 的轻,可以拆成三点来看:磁盘上操作系统文件的共享、内存中操作系统页面的共享,以及与主机之间内存分配的协同。
4.1. 动态基础映像:500MB 跑出完整的 Windows
Windows Sandbox 是由虚拟机监控程序隔离出来的、用完即弃的 Windows 桌面。关掉后一切消失,下次会以全新状态在几秒内启动。1
先让人费解的是磁盘。明明能启动完整的 Windows,Sandbox 的基础映像安装后却只有约 500MB,分发时压缩后只有 30MB。2 秘密在于动态基础映像。
- 操作系统文件的绝大部分是不可变(immutable)的,可以直接共享主机上的那一份。
- 可变(mutable)的少数文件无法共享,因此在基础映像里保留一份干净的副本。
- 启动时把主机的不可变文件与本地可变文件的副本组合起来,构成完整的 Windows 映像。2
也就是说,Sandbox 既不下载也不保存 Windows 的副本,而是复用主机上已安装的 Windows 来启动。
flowchart TB
accTitle: 动态基础映像的构成
accDescr: 主机 Windows 中不可变的操作系统文件直接共享,只有可变文件在基础映像里保留干净副本,两者组合起来构成 Sandbox 的完整 Windows 映像
hostw["主机上的整套 Windows"] --> imm["不可变的操作系统文件(绝大多数)"]
hostw --> mut["可变的操作系统文件(少数)"]
imm -->|直接共享| img["Sandbox 的启动映像"]
mut -->|保留干净的副本| img
img --> boot["作为完整的 Windows 启动"]
img -.-> size["需要保存的只有约 500MB"]
图7:它不是「再拥有一个 Windows」,而是「从主机的 Windows 组装出来」,这就是不再复制磁盘的形态。
正因为是这样的构成,下面这套生命周期才成立。
另外要说明,被丢弃的是 Sandbox 内部的本地状态。
如果用 .wsb 配置文件把主机的文件夹以可写方式映射了进来,对它的修改会留在主机一侧。6
flowchart TB
accTitle: Windows Sandbox 的生命周期
accDescr: 启动后几秒内准备好一个全新的 Windows,做完应用验证或实验后关闭,Sandbox 内的状态全部丢弃,下次仍从全新状态开始,但对以可写方式映射进来的主机文件夹所做的修改会保留下来
launch["启动(数秒)"] --> clean["全新的 Windows"]
clean --> work["应用验证与实验"]
work --> close2["关闭"]
close2 --> discard["丢弃 Sandbox 内的全部状态"]
discard -.-> mapped["映射进来的可写文件夹中的修改会留在主机上"]
discard -->|下次启动| launch
图8:每次都能回到全新状态,是因为可变部分本来就是用完即弃的副本,「抹掉」本身就是设计的一部分。
4.2. 直接映射:同一个 ntdll.dll 就是同一个物理页
被共享的不只是磁盘,还有内存。由于 Sandbox 运行的是与主机相同的操作系统映像,对于操作系统二进制文件,它采用一种叫「直接映射」的技术,与主机使用相同的物理内存页。当 Sandbox 内把 ntdll.dll 读入内存时,它指向的正是主机上加载的同一个二进制的同一批物理页。
这样既不会把主机的秘密置于危险之中,又实现了比传统虚拟机小得多的内存占用。2
「让多个使用者共用同一个物理页」——这与内存系列第3回追踪过的、由节对象实现的 DLL 共享(「节对象与写时复制」)是同一个思路。那套机制做的是进程之间的共享,而 Sandbox 把它跨越虚拟机边界做了出来。
flowchart TB
accTitle: 直接映射带来的物理页共享
accDescr: 主机上的应用与 Sandbox 内的应用,对 ntdll 等操作系统二进制文件共用同一批物理内存页,从而减少内存占用
happ["主机上的应用"] --> hva["主机侧的虚拟地址"]
sapp["Sandbox 内的应用"] --> sva["Sandbox 侧的虚拟地址"]
hva --> phys["同一批物理页(ntdll.dll 等操作系统二进制文件)"]
sva --> phys
phys -.-> save["不必再为操作系统复制一份 RAM"]
图9:把一直用于进程之间的页面共享思路,跨越虚拟机边界用起来,就是直接映射。
4.3. 内存的借与还:与其说像虚拟机,不如说像进程
相对于传统虚拟机的静态内存分配,作为 Sandbox 地基的容器技术会与主机协同、动态决定资源分配。主机内存吃紧时,可以像从普通进程回收那样,也从容器回收内存。2 Hyper-V 的动态内存虽然也能在设定范围内增减分配给虚拟机的量,但 Sandbox 更进一步:它与主机的内存管理站在同一个平台上互相调剂,这是两者的差别。
flowchart TB
accTitle: 主机与 Sandbox 之间的内存协同
accDescr: 传统虚拟机以静态大小独占为主且调整手段有限,而 Sandbox 会随主机的内存压力成为回收对象,与普通进程站在同一个平台上互相调剂内存
pressure["主机的内存压力上升"] --> from{"从哪里回收?"}
from --> proc["普通进程的 Working Set"]
from --> sbx["Sandbox(容器)的占用部分"]
proc --> relief["腾出空闲内存"]
sbx --> relief
relief -.-> contrast["传统虚拟机可调整的手段有限"]
图10:在内存调剂这件事上,Sandbox 站的是进程那一边而不是虚拟机那一边,主机吃紧时它会让出来。
第1回讲过「虚拟机的性能也取决于主机一侧」,而在轻量虚拟机上更进一步:内存分配本身就是与主机的共同作业。Sandbox 之所以用起来不像「沉重的虚拟化软件」,而更像「又一个应用」,靠的就是这种协同。
另外,把 Sandbox 用于业务应用验证的具体步骤,已在既有文章「用 Windows Sandbox 搭建业务应用验证环境」中讲过。本文写的是它脚下的机制。
5. 容器 ── 隔离的线画在哪里
这里不要只凭「容器」这个名字判断安全性,而要确认它到底是与主机共享内核,还是连内核一起分开。
5.1. 进程隔离与 Hyper-V 隔离
Windows 容器有两种运行时隔离模式。映像是通用的,启动时用标志选择。7
- 进程隔离:多个容器与主机共享内核,通过文件系统、注册表、网络端口、进程 ID 空间、对象管理器命名空间等按命名空间的虚拟化来分离。这与 Linux 容器几乎是同一种方式。
- Hyper-V 隔离:每个容器都运行在高度优化的虚拟机中,实质上拥有专用内核。由于虚拟机的存在,容器彼此之间以及与主机之间都隔着硬件级别的分离。7
基于命名空间的分离,可以说是注册表虚拟化那篇文章(「Windows 的注册表重定向与虚拟化」)里看到的「在同一套 API 之下展示不同实体」手法的彻底版。
flowchart TB
accTitle: 进程隔离与 Hyper-V 隔离的对比
accDescr: 进程隔离下容器与主机共享内核并靠命名空间分离,Hyper-V 隔离下每个容器在优化过的虚拟机内拥有专用内核
subgraph pi ["进程隔离"]
c1["容器 A"] --> sk1["与主机共享的内核"]
c2["容器 B"] --> sk1
end
subgraph hi ["Hyper-V 隔离"]
c3["容器 C"] --> k3["专用内核(优化虚拟机内)"]
c4["容器 D"] --> k4["专用内核(优化虚拟机内)"]
end
sk1 ~~~ c3
图11:即使是同一个容器映像,把隔离的线画在内核之上,还是连内核一起分开,都可以在启动时选。
5.2. 哪一个才配称「安全边界」
这两种模式的差别不止于性能。Microsoft 并不把进程隔离的容器视为坚固的安全边界。作为安全边界来维护(修补漏洞)的是虚拟机监控程序隔离的容器;在存在敌意的多租户场景中,应当选择 Hyper-V 隔离。8
第2回看到的 VBS,同样是以「内核可能被攻破」为前提,把秘密撤到虚拟机监控程序边界之后。在容器的世界里,同一条判断标准依然成立:把不可信代码关起来的那条线,不画在共享内核的内侧,而画在虚拟机监控程序的边界上。
flowchart TB
accTitle: 按代码的可信程度选择隔离方式
accDescr: 工作负载可信就用进程隔离换取密度与性能,代码不可信或来自他人就选择虚拟机监控程序边界,例如 Hyper-V 隔离容器、关闭网络等功能的强化配置 Windows Sandbox 或隔离的虚拟机
trust{"这段代码可信吗?"} -->|可信| dens["进程隔离(优先密度与速度)"]
trust -->|不可信或来自他人| bound["选择虚拟机监控程序边界"]
bound --> opt1["Hyper-V 隔离容器"]
bound --> opt2["强化配置的 Sandbox 或隔离虚拟机"]
图12:隔离模式首先是安全问题,其次才是性能问题,是可信程度决定了线画在哪里。
补充:在虚拟机里使用时,要确认嵌套虚拟化的要求
在 Hyper-V 虚拟机里运行 Hyper-V 隔离容器,会形成虚拟机监控程序叠成两层的嵌套虚拟化。
一层嵌套在满足条件的环境中(Intel 处理器要求主机为 Windows 10/Windows Server 2016 以上,AMD 处理器要求主机为 Windows 11/Windows Server 2022 以上,以及各自对应的虚拟机配置版本)在生产环境中也受支持,此外还要求把虚拟化辅助功能公开给外层虚拟机的设置(Hyper-V 上是 Set-VMProcessor 的 ExposeVirtualizationExtensions)。
在虚拟机里运行 WSL2 的组合同样受支持。9 云上的开发虚拟机能不能用 WSL2 或 Docker,也取决于该虚拟机规格与配置是否公开了嵌套虚拟化。
flowchart TB
accTitle: 嵌套虚拟化的结构
accDescr: 物理主机的虚拟机监控程序之上是云虚拟机,其中再运行一层虚拟机监控程序(受支持的嵌套最多一层)来支撑 WSL2 与 Hyper-V 隔离容器
phys3["物理主机的虚拟机监控程序"] --> cvm["云虚拟机(开发机器)"]
cvm --> nhv["虚拟机内的虚拟机监控程序(嵌套第 1 层)"]
nhv --> w2["WSL2"]
nhv --> hvc["Hyper-V 隔离容器"]
nhv -.-> limit["受支持的嵌套最多一层"]
图13:云虚拟机里之所以能跑 wsl,是因为官方只支撑到一层嵌套虚拟化。
5.3. 隔离与轻量的光谱
把到此为止登场的角色排到一条轴上,就是下面这样。
flowchart TB
accTitle: 隔离强度与轻量程度的光谱
accDescr: 进程隔离容器最轻但共享内核,WSL2、Sandbox 与 Hyper-V 隔离容器是拥有专用内核的轻量虚拟机(Sandbox 靠与主机共享,WSL2 靠特化内核),完整虚拟机最重但最通用
ax["轻 ← → 重"] ~~~ p1
p1["进程隔离容器(共享内核)"] --> p2["WSL2、Sandbox、Hyper-V 隔离(拥有专用内核的轻量虚拟机)"]
p2 --> p3["完整虚拟机(什么都能跑,副本全都自己带)"]
p1 -.-> n1["边界:命名空间"]
p2 -.-> n2["边界:虚拟机监控程序"]
p3 -.-> n3["边界:虚拟机监控程序+完全独立"]
图14:轻量虚拟机这一群是保住虚拟机监控程序边界、只削掉复制的折中解,而削法上 Sandbox 走共享、WSL2 走特化内核。
6. 用自己的眼睛确认
轻与共享,都可以在自己机器上观测到。
6.1. WSL2 的启动时间与内存增减
开着任务管理器,执行下面这些命令看看。
# 感受启动时间(初次要启动虚拟机,第二次以后更快)
Measure-Command { wsl -e true }
# WSL2 虚拟机的内存占用(vmmem / Virtual Machine Memory)
Get-Process -Name vmmem* | Select-Object Name, WorkingSet64
# 观察连虚拟机一起关闭后内存被归还的样子
wsl --shutdown
在 WSL2 里做大型构建或文件操作时 vmmem 会长大,而 wsl --shutdown 会让它一口气还回去,这些都能观测到。
6.2. WSL2 中文件放置带来的速度差
把同一个仓库分别放到 Linux 侧(~/repo)和 Windows 侧(/mnt/c/repo),比较 git status 和解压处理的耗时,第3.2节说的差距就会变成具体数字。
6.3. 启动 Sandbox 时主机侧内存的增量
启动 Sandbox,在主机的任务管理器里看内存的增量。增量远小于「又多了一个 Windows」给人的想象,这正说明了共享的效果。
想进一步深挖主机侧的内存构成,介绍 RAMMap 与 VMMap 用法的 Sysinternals 工具文章(「Process Explorer、Handle 与 VMMap 的用法」)可以参考。
不过这些工具看的是主机侧进程与物理内存的分类,并不能直接观测与客户机之间的共享本身。
6.4. Windows 容器隔离模式的差别
如果手头有 Windows 容器环境,用 docker run --isolation=process 和 --isolation=hyperv 启动同一个映像,比较启动时间和任务管理器里的呈现(进程隔离时容器内的进程会出现在主机的进程列表里),就能体会到隔离线的位置。7
不过进程隔离以主机与映像版本一致为前提,在客户端操作系统上仅限开发与测试用途。Hyper-V 隔离允许更宽的组合,所以比较时请使用兼容的组合。10
7. 实务中要避开的三种误读
7.1. 「WSL2 很慢」
慢的不是 WSL2,而是跨越操作系统边界的文件 I/O 路径。很多情况下,只要把项目挪到 Linux 侧,体感就完全不同。4 反过来,把要用 Windows 工具操作的文件放到 Linux 侧,出于同样的理由同样不利。请按「放在使用它的那一侧操作系统」来判断。
7.2. 「vmmem 膨胀就是内存泄漏」
WSL2 的内存随需求增减,释放的部分会被归还。用现行的 WSL 时,文件缓存也由 autoMemoryReclaim(默认是 dropCache)自动回收,所以「一直很大」的状态多半会随时间缓解。5
若仍然留着,先确认 autoMemoryReclaim 是不是被设成了 disabled、负责归还释放部分的 pageReporting 是不是被关掉了(或者是不是旧版 WSL),然后用 .wslconfig 的 memory 明确上限,或在会话告一段落时用 wsl --shutdown 全部归还。
判断是不是泄漏的思路,与内存系列的导入篇「Windows 的「内存使用量」究竟表示什么」相同。
7.3. 「放进容器就安全了」
进程隔离的容器共享内核,按 Microsoft 的标准它不是安全边界。8 运行不可信代码或样本时,请选择 Hyper-V 隔离的容器、Windows Sandbox 或专用虚拟机这类具备虚拟机监控程序边界的隔离。
不过,虚拟机监控程序边界并不是万能的免罪符。
Windows Sandbox 的默认设置启用网络连接,可能把不可信的应用暴露给内部网络。1 如果要用它跑样本,请用 .wsb 配置文件关闭网络与剪贴板重定向来加强隔离,或者改用隔离网络上的专用虚拟机。
8. 总结 ── 为系列收尾
第3回的要点如下。
- 轻量虚拟机的「轻」不是「削弱了隔离」的结果,而是「不再复制」的结果。
- WSL2 在被管理的轻量实用虚拟机中运行真正的 Linux 内核,发行版作为虚拟机内的容器被隔离开。3 文件放在使用它的那一侧操作系统是性能上的原则;内存会动态增减,可用
.wslconfig控制上限。45 - Windows Sandbox 用动态基础映像共享主机的不可变操作系统文件,用直接映射共享目标操作系统二进制文件的物理页,因此并不持有整套 Windows 的副本。2 可变文件的约 500MB,以及在里面运行的应用自身的内存,则要另外算。
- 容器的隔离模式可以在启动时选择,而配称安全边界的是 Hyper-V 隔离那一侧。78
把整个系列压成一张图,就是这样。
- 第1回:Windows 之下有一层虚拟机监控程序,宿主操作系统自身作为根分区运行。CPU 与内存(SLAT)的仲裁由这一层直接完成,合成设备的 I/O 则在 VMBus 的另一端由根分区(VSP)居中转发。
- 第2回:这一层不只用于虚拟机之间的分离,也用于在同一个操作系统内部画出比内核更强的边界(VTL)。Windows 11 的默认安全能力就建在它之上。
- 第3回:在同一层之上,靠削掉复制成就了「数秒即可启动的虚拟机」。隔离的线原样保留,它却成了日常的工具。
flowchart TB
accTitle: 整个系列的一张全景图
accDescr: 硬件之上的虚拟机监控程序对应第1回,宿主 Windows 内 VTL0 与 VTL1 的分离对应第2回,同一层之上 WSL2、Sandbox 与 Hyper-V 隔离的轻量对应第3回,进程隔离容器共享主机的内核,Sandbox 靠共享而 WSL2 靠特化内核变轻
hw3["硬件"] --> hv3["虚拟机监控程序(第1回)"]
hv3 --> rp3["宿主 Windows(VTL 分离见第2回)"]
hv3 --> lw3["WSL2、Sandbox、Hyper-V 隔离(第3回)"]
rp3 --> pc3["进程隔离容器(共享内核)"]
lw3 -.-> mech3["Sandbox 靠共享,WSL2 靠特化内核减重"]
图15:把三回叠起来,就是当今 Windows 脚下的全景。
虚拟化早已不再是机房里的技术,也不再只属于要建虚拟机的人。它就在你的 Windows 脚下,静静支撑着安全与开发体验这两头——这就是它现在的位置。
相关文章
- Windows 虚拟化的深层(第1回) ── 你的 Windows 实际在哪里运行:虚拟机监控程序与分区
- Windows 虚拟化的深层(第2回) ── 连内核也看不见的内存:VBS、HVCI 与 Credential Guard 的机制
- Windows 内存的深层(第3回) ── 节对象与写时复制
- 用 Windows Sandbox 搭建业务应用验证环境
- Windows 的注册表重定向与虚拟化
相关咨询领域
小村软件有限公司承接使用 WSL2 与容器的开发环境搭建、Windows 应用验证环境设计,以及虚拟化环境下的性能与兼容性调查。
参考链接
-
Microsoft Learn, Windows Sandbox. 关于 Windows Sandbox 作为用完即弃的虚拟机在数秒内启动、关闭后一切丢弃,用 Microsoft 虚拟机监控程序运行另一个内核以与主机分离,以及默认启用网络连接且可用配置文件关闭。 ↩ ↩2 ↩3
-
Microsoft Learn, Windows Sandbox architecture. 关于动态基础映像用共享主机的不可变操作系统文件与可变文件的干净副本构成完整 Windows 映像(安装后约 500MB),相对传统虚拟机的静态内存分配,容器会与主机协同动态分配且主机可回收其内存,以及直接映射让 ntdll.dll 等操作系统二进制文件与主机使用同一批物理页。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, What is the Windows Subsystem for Linux?. 关于 WSL2 在轻量实用虚拟机中运行 Linux 内核,以及各个发行版作为隔离容器运行、共享网络命名空间与内核而分离 PID、挂载、用户等命名空间。 ↩ ↩2 ↩3
-
Microsoft Learn, Comparing WSL Versions. 关于 WSL2 的内核由 Microsoft 从 Stable 分支构建,Store 分发版 WSL 把更新从操作系统映像中剥离出来作为包接收并用
wsl --update应用(Windows 内置的旧分发方式则经由 Windows Update),解压 tarball 最多快 20 倍等性能例子,跨操作系统文件系统的性能上 WSL1 更胜一筹因而应把文件放到使用它的那一侧操作系统,以及内存会增减、释放的部分会被归还但缓存有时要到虚拟机退出才返还。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, Advanced settings configuration in WSL. 关于可在 .wslconfig 的 [wsl2] 小节里设定 WSL2 整台虚拟机的内存上限、处理器数、交换空间以及 pageReporting(默认启用,负责检测并归还未使用内存),以及实验性设置 autoMemoryReclaim 的默认值为 dropCache 会自动回收缓存内存。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Use and configure Windows Sandbox. 关于可用 .wsb 配置文件的 MappedFolders 把主机的文件夹以只读或可写方式共享进来。 ↩
-
Microsoft Learn, Isolation Modes. 关于 Windows 容器的进程隔离与主机共享内核并靠命名空间分离,Hyper-V 隔离在优化过的虚拟机内实质上拥有专用内核,以及同一个映像可在启动时用标志选择任一模式运行。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Secure Windows containers. 关于只有虚拟机监控程序隔离的容器被视为安全边界,进程隔离的容器不被视为坚固的安全边界,以及在存在敌意的多租户场景中应选择虚拟机监控程序隔离。 ↩ ↩2 ↩3
-
Microsoft Learn, What is Nested Virtualization?. 关于在 Hyper-V 虚拟机内运行 Hyper-V 隔离容器(一层嵌套)在生产环境中受支持,要求 Intel 处理器的主机为 Windows Server 2016/Windows 10 以上、AMD 处理器的主机为 Windows Server 2022/Windows 11 以上并配以各自对应的虚拟机配置版本,前提条件是把虚拟化辅助功能公开给外层虚拟机的设置(ExposeVirtualizationExtensions),以及在 Hyper-V 虚拟机内运行 WSL2 同样受支持。 ↩
-
Microsoft Learn, Windows container version compatibility. 关于进程隔离以主机与容器映像版本一致为前提,Hyper-V 隔离可运行与主机不同操作系统版本的映像,以及客户端操作系统上的进程隔离仅限开发与测试用途。 ↩
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
Windows 虚拟化的深层(第 1 回)── 你的 Windows 究竟运行在哪里:虚拟机监控程序与分区
启用 Hyper-V 之后,主机 Windows 自身会作为根分区运行在虚拟机监控程序之上。本文从 VT-x、SLAT、VMBus 的职责讲起,说清虚拟化的底层基础。
Windows 虚拟化的深层(第 2 回)── 连内核也读不到的内存:VBS、HVCI 与 Credential Guard 的机制
在兼容硬件上全新安装时默认启用的 VBS,用虚拟机监控程序与 SLAT 造出比内核更强的隔离。本文讲解 VTL、安全内核、HVCI 与 Credential Guard 的结构。
用 Windows Sandbox 加快应用验证的方法
本文整理如何利用 Windows Sandbox 提升管理员权限问题排查、干净环境复现、权限不足与资源不足复现的效率,并说明 .wsb 与 CLI 的分工使用方式。
为什么“剩余1秒”迟迟不结束?── 进度条与剩余时间的工作原理
剩余1秒持续很久、卡在99%、一直显示准备中,分别是怎么回事?从进度的分母、速度预测、最后的处理步骤和界面更新逐一解释,并提供同一任务不同进度显示的交互演示。
Windows 共享文件夹为什么时好时坏——排查 Kerberos、NTLM 与凭据问题
通过症状和日志排查 Windows 共享文件夹时而能访问、时而无法访问的问题。说明 IP 与名称的差异、仅应用失败、空密码、1219、重启及 SMB 签名的检查步骤,以及每项结果能证明什么。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
常见问题
汇总了咨询这一主题时常见的问题。
- WSL2 是虚拟机吗?
- 是。WSL2 在轻量实用虚拟机中运行由 Microsoft 构建的真正 Linux 内核。不过虚拟机由 WSL 在幕后管理,因此设计上不会让使用者去操心虚拟机设置或等待启动。各个 Linux 发行版都作为隔离的容器运行在这台被管理的虚拟机中。
- WSL2 里操作 /mnt/c 下的文件为什么慢?
- 因为从 WSL2 的 Linux 内核访问 Windows 侧的文件系统,要经过跨越操作系统边界的文件共享。对 Linux 文件系统(ext4 虚拟磁盘)的操作很快,所以原则是把项目文件放在操作它的工具所在的那一侧操作系统。
- vmmem 进程占用的内存很大,是泄漏吗?
- 多数情况下不是泄漏。WSL2 的内存随使用量增减,进程释放的内存会在默认启用的 pageReporting 设置下还给 Windows。文件缓存那部分,在现行的 WSL 中也由 .wslconfig 的 autoMemoryReclaim(默认是 dropCache)自动回收。在关闭了这些设置的环境或旧版 WSL 上,内存可能会一直留到虚拟机退出;那种情况下可用 memory 设置上限,或用 wsl --shutdown 归还。
- Windows Sandbox 为什么能用几百 MB 的磁盘启动完整的 Windows?
- 靠的是叫作动态基础映像的机制:共享主机上已安装的 Windows 中那些不可变的操作系统文件,只为少数可变文件保留一份干净的副本。这样就无需保存整套 Windows 的副本,也能组装出可启动的完整映像。
- 容器比虚拟机更安全吗?
- 取决于隔离模式。进程隔离的容器与主机共享内核,Microsoft 并不把它视为坚固的安全边界。要处理敌意代码时,需要选择让每个容器都拥有专用内核的 Hyper-V 隔离。