更新紀錄(僅初版,2026年08月22日 發布)
- 初次發布
引用本文(DOI(已登錄存檔): 10.5281/zenodo.22176925)
以下 DOI 指向先前登錄的存檔,內容可能與目前正文不同。引用目前正文時,請使用本頁網址。
Go Komura(2026)。〈Windows 虛擬化的深層(第 3 回)── 幾秒就啟動的虛擬機器:WSL2、Windows Sandbox 與容器為何這麼輕〉。小村軟體有限公司。 https://comcomponent.com/zh-TW/blog/windows-virtualization-internals-wsl2-sandbox-containers/
- DOI(已登錄存檔)
- 10.5281/zenodo.22176925
- DOI(上次登錄版本)
- 10.5281/zenodo.22176926
完整虛擬機器那麼重,WSL2 與 Windows Sandbox 為何這麼輕? 系列最終回不只從「要隔離什麼」,也要從「什麼可以不必複製」來說明這個差別。
在 Hyper-V 管理員裡建立一台 Windows 虛擬機器,開機要花幾十秒,還會獨佔數 GB 記憶體。可是在同一台 PC 上輸入 wsl,幾秒之內 Linux 殼層就會回來;Windows Sandbox 也在幾秒內開出一個用完即丟的桌面。1
它們的地基都是第 1 回看到的 Windows Hypervisor。第 2 回確認了:用這層地基可以造出比核心更強的隔離。本文則分開來看 WSL2 的用途特化、Sandbox 的共用、容器的隔離模式。
「Windows 虛擬化的深層」全 3 回
同一套 Windows Hypervisor,依 地基 → 安全隔離 → 輕量虛擬機器的應用 的順序來看。
| 回 | 核心問題 |
|---|---|
| 第 1 回:Hypervisor 與分割區 | 主機的 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. 先講結論
輕量虛擬機器守住了隔離線(專用核心與 Hypervisor 邊界),只把「整套客體作業系統的複本」減掉。Sandbox 直接共用主機的 Windows 本身,WSL2 把客體換成用途特化的小型 Linux,而兩者的記憶體都不是固定保留,而是與主機動態借還。
完整虛擬機器之所以重,源頭不是隔離本身,而是複製:磁碟上再放一份作業系統映像,RAM 裡再佔一份作業系統的分頁,每次啟動再走一遍完整開機。輕量虛擬機器用兩條方針切掉這些複製——「能安全共用的就共用」(Sandbox)、「不能共用就重做成小的」(WSL2)。
flowchart TB
accTitle: 支撐輕量虛擬機器的三種共用
accDescr: 完整虛擬機器原本複製的作業系統映像,在 Sandbox 上改成共用、在 WSL2 上改成縮小;以固定配置為主(動態記憶體設定屬於例外)的記憶體改成與主機動態調度;啟動改成輕量核心與最小設定,最後只留下隔離的邊界
heavy["完整虛擬機器之所以重,源頭是複製"] --> d1["磁碟:複製一份作業系統映像"]
heavy --> d2["記憶體:以固定配置為主"]
heavy --> d3["啟動:從頭再走一遍完整開機"]
d1 -->|改成| s1["共用(Sandbox)或縮小(WSL2)"]
d2 -->|改成| s2["與主機動態借還"]
d3 -->|改成| s3["用輕量核心與最小設定縮短"]
圖 1: 它們停掉的不是隔離而是複製,這就是「同一個 Hypervisor 卻更輕」的答案骨架。
以下依 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: Hypervisor 之上並坐著主機 Windows 與輕量公用虛擬機器,虛擬機器裡執行 Microsoft 打造的 Linux 核心,各發行版在其中作為隔離的容器執行
hv["Hypervisor"] --> 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 的輕,可以拆成三點來看:磁碟上作業系統檔案的共用、RAM 裡作業系統分頁的共用,以及與主機之間記憶體調配的協調。
4.1. 動態基礎映像:500MB 跑出完整的 Windows
Windows Sandbox 是由 Hypervisor 隔離出來、用完即丟的 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 就是同一個實體分頁
被共用的不只是磁碟,還有 RAM。由於 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 並不把處理程序隔離的容器視為堅固的安全邊界。作為安全邊界來維護(修補漏洞)的是 Hypervisor 隔離的容器;在具敵意的多租戶情境中,應當選擇 Hyper-V 隔離。8
第 2 回看到的 VBS,同樣是以「核心可能被攻破」為前提,把祕密撤到 Hypervisor 邊界之後。在容器的世界裡,同一條判斷標準依然通用:把不可信任的程式碼關起來的那條線,不畫在共用核心的內側,而畫在 Hypervisor 的邊界上。
flowchart TB
accTitle: 依程式碼的信任程度選擇隔離方式
accDescr: 工作負載可信任就用處理程序隔離換取密度與效能,程式碼不可信任或來自他人就選擇 Hypervisor 邊界,例如 Hyper-V 隔離容器、關掉網路等功能的強化設定 Windows Sandbox 或隔離的虛擬機器
trust{"這段程式碼可以信任嗎?"} -->|可以| dens["處理程序隔離(優先密度與速度)"]
trust -->|不行或來自他人| bound["選擇 Hypervisor 邊界"]
bound --> opt1["Hyper-V 隔離容器"]
bound --> opt2["強化設定的 Sandbox 或隔離虛擬機器"]
圖 12: 隔離模式首先是安全議題,其次才是效能議題,是信任程度決定了線畫在哪裡。
補充:在虛擬機器裡使用時,要確認巢狀虛擬化的需求
在 Hyper-V 虛擬機器裡執行 Hyper-V 隔離容器,會形成 Hypervisor 疊成兩層的巢狀虛擬化。
一層巢狀在符合條件的環境中(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: 實體主機的 Hypervisor 之上是雲端虛擬機器,其中再執行一層 Hypervisor(受支援的巢狀最多一層)來支撐 WSL2 與 Hyper-V 隔離容器
phys3["實體主機的 Hypervisor"] --> cvm["雲端虛擬機器(開發機器)"]
cvm --> nhv["虛擬機器裡的 Hypervisor(巢狀第 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["邊界:Hypervisor"]
p3 -.-> n3["邊界:Hypervisor+完全獨立"]
圖 14: 輕量虛擬機器這一群是守住 Hypervisor 邊界、只切掉複製的折衷解,而切法上 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 或專用虛擬機器這類具備 Hypervisor 邊界的隔離。
不過,Hypervisor 邊界並不是萬能的免罪符。
Windows Sandbox 的預設設定啟用網路連線,可能把不可信任的應用程式暴露給內部網路。1 若要用它跑檢體,請用 .wsb 設定檔關掉網路與剪貼簿重新導向來加強隔離,或者改用隔離網路上的專用虛擬機器。
8. 總結 ── 為系列收尾
第 3 回的重點如下。
- 輕量虛擬機器的「輕」不是「削弱了隔離」的結果,而是「停掉複製」的結果。
- WSL2 在受管理的輕量公用虛擬機器裡執行真正的 Linux 核心,發行版作為虛擬機器裡的容器被隔離開來。3 檔案放在使用它的那一側作業系統是效能上的原則;記憶體會動態增減,可用
.wslconfig控制上限。45 - Windows Sandbox 用動態基礎映像共用主機的不可變作業系統檔案,用直接對應共用目標作業系統二進位檔的實體分頁,因此並不持有整套 Windows 的複本。2 可變檔案的約 500MB,以及在裡面執行的應用程式自身的記憶體,則要另外算。
- 容器的隔離模式可以在啟動時選擇,而配稱安全邊界的是 Hyper-V 隔離那一側。78
把整個系列壓成一張圖,就是這樣。
- 第 1 回:Windows 之下有一層 Hypervisor,主機作業系統自身作為根分割區執行。CPU 與記憶體(SLAT)的調停由這一層直接處理,合成裝置的 I/O 則在 VMBus 的另一端由根分割區(VSP)居中轉送。
- 第 2 回:這一層不只用於虛擬機器之間的分離,也用於在同一個作業系統內側畫出比核心更強的邊界(VTL)。Windows 11 的預設安全能力就蓋在它之上。
- 第 3 回:在同一層之上,靠切掉複製成就了「幾秒就啟動的虛擬機器」。隔離的線原樣保留,它卻成了日常的工具。
flowchart TB
accTitle: 整個系列的一張全景圖
accDescr: 硬體之上的 Hypervisor 對應第 1 回,主機 Windows 裡 VTL0 與 VTL1 的分離對應第 2 回,同一層之上 WSL2、Sandbox 與 Hyper-V 隔離的輕量對應第 3 回,處理程序隔離容器共用主機的核心,Sandbox 靠共用而 WSL2 靠特化核心變輕
hw3["硬體"] --> hv3["Hypervisor(第 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 其實跑在哪裡?Hypervisor 與分割區
- Windows 虛擬化的深層(第 2 回)── 連核心都看不到的記憶體:VBS、HVCI 與 Credential Guard 如何運作
- Windows 記憶體的深層(第 3 回)── 區段物件與寫時複製
- 用 Windows Sandbox 打造商務應用程式驗證環境
- Windows 的登錄檔重新導向與虛擬化
相關諮詢領域
小村軟體有限公司承接使用 WSL2 與容器的開發環境整備、Windows 應用程式驗證環境設計,以及虛擬化環境下的效能與相容性調查。
參考連結
-
Microsoft Learn, Windows Sandbox. 關於 Windows Sandbox 作為用完即丟的虛擬機器在數秒內啟動、關掉後一切丟棄,用 Microsoft Hypervisor 執行另一個核心以與主機分離,以及預設啟用網路連線且可用設定檔關掉。 ↩ ↩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. 關於只有 Hypervisor 隔離的容器被視為安全邊界,處理程序隔離的容器不被視為堅固的安全邊界,以及在具敵意的多租戶情境中應選擇 Hypervisor 隔離。 ↩ ↩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 究竟跑在哪裡:Hypervisor 與分割區
啟用 Hyper-V 之後,主機 Windows 本身會以根分割區的身分跑在 Hypervisor 之上。本文從 VT-x、SLAT、VMBus 的職責講起,說清虛擬化的底層基礎。
Windows 虛擬化的深層(第 2 回)── 連核心也讀不到的記憶體:VBS、HVCI 與 Credential Guard 的運作方式
在相容硬體上全新安裝時預設啟用的 VBS,用 Hypervisor 與 SLAT 做出比核心更強的隔離。本文解說 VTL、安全核心、HVCI 與 Credential Guard 的結構。
用 Windows 沙箱加速 Windows 應用程式開發的驗證 - 以實務向整理管理員權限問題、乾淨環境、權限不足・資源不足的重現
整理在 Windows 應用程式開發中如何運用 Windows Sandbox 加速驗證的實務做法。透過按情境分檔的 .wsb、唯讀輸入與專用 Outbox 寫入分離、在容器內另建標準使用者重現權限不足、以及降低記憶體和關閉 vGPU 製造資源不足偏向,把每次的乾淨環境準備...
為什麼「剩餘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 隔離。