TL;DR 核心結論: WSL 2 與 Docker 的虛擬硬碟採用動態擴充機制,在 Linux 內部刪除檔案後並不會自動將空間還給 Windows。標準的兩階段瘦身策略為:第一階段在 Linux 內部執行清理並透過
sudo fstrim -v /標記未使用區塊;第二階段徹底退出 Docker 與 WSL,在 Windows 端以系統管理員身分透過diskpart的compact vdisk命令進行實體收縮。本次實測成功讓 C 槽剩餘空間從 104 GB 躍升至 290 GB,一口氣找回 186 GB 的可用容量。
在日常開發環境中,Docker 已經是幾乎必不可少的工具。然而,雖然在 Windows 上可以透過 WSL 2 來順暢運作 Docker Desktop,但隨著專案持續迭代、頻繁執行 docker build 建構映像檔,以及背景啟動各類資料庫與微服務測試容器,某天打開檔案總管,往往會赫然發現 C 槽剩餘空間拉起警報。

這是我前陣子的親身經歷:我的 C 槽總容量為 952 GB,可用空間一路跌到了僅剩 104 GB。元兇也很好抓,因為近期我使用 Hermes Agent 做了不少實驗與專案開發,其中許多環節都有使用到 Docker,一查才發現 WSL 2 / Docker 存放 Linux 檔案系統的虛擬磁碟,擴張到了近 200 GB 的大小。
更令人困擾的是,即使進入 Docker 刪除了所有退役的容器與舊映像檔,Windows 宿主機上的 C 槽剩餘空間依然完全沒有釋放。
因此,這篇文章就來跟大家分享一下,該如何真正對 WSL 的虛擬磁碟進行物理瘦身,並深入探討這套方法在其他虛擬磁碟(如 Hyper-V)上的通用性。
原理剖析:為什麼 WSL 2 的虛擬硬碟「只長大、不縮小」?
在 WSL 2 與 Docker 環境中,儲存資料的虛擬硬碟皆採用微軟的第二代虛擬硬碟格式(VHDX,Virtual Hard Disk v2)。
許多人常以為虛擬硬碟一律叫 ext4.vhdx,但其實兩者有明確分工:
- Docker Desktop:真正存放所有映像檔、容器、資料卷與建構快取的檔案名稱通常是
docker_data.vhdx(這正是吃掉近 200 GB 的真正元兇);至於幾百 MB 的輕量系統環境檔案才是ext4.vhdx。 - 一般 WSL 2 發行版(如 Ubuntu):系統根磁碟檔案名稱則預設為
ext4.vhdx。
這兩者在 Windows 中皆預設採用 動態擴充(Dynamically Expanding) 機制:
- 按需索取空間: 當你在 Linux 中下載套件、建構 Docker 映像檔或寫入大量檔案時,底層驅動會向 Windows 宿主機即時索取實體儲存空間,檔案體積因而持續膨脹。
- 刪除不主動回縮: 當你在 Linux 內部刪除檔案時,Linux 核心僅是將對應的磁區標記為「空閒區塊(Free Blocks)」。宿主機的 Windows 檔案系統並無法得知虛擬磁碟內部哪些資料已經無效,因此 VHDX 的實體大小不會自動縮減。
要真正回收空間,必須在內部先清理無效資料並標記區塊,然後在外部將虛擬磁碟進行實體壓縮與釋放。
第一階段:Linux 與 Docker 內部大掃除與區塊標記
1. 清理 Docker 映像檔、容器與建構快取
啟動 CMD (Windows 終端機),執行以下指令清理 Docker 累積的龐大資料:
|
|
重要提醒:
docker system prune -a --volumes會清除所有已停止運作的容器、未被引用的映像檔以及未命名的匿名磁碟區 (Anonymous Volumes)。如果容器內有重要資料庫檔案,請務必先確認資料已掛載於具名磁碟區 (Named Volume) 或有完整備份。
2. 清理 Linux 系統快取
接著我們要進到 wsl 內,清理 Linux 套件管理器與日常開發工具累積的快取檔案:
此步驟主要是 WSL 使用,如果是只有 docker 的話就不用做了
先使用 wsl -d <發行版> 的指令進入 wsl 的終端機,例如:
|
|
然後執行以下指令清理 APT 套件快取與不再需要的孤立套件:
|
|
3. 執行 fstrim 標記未使用區塊
fstrim 是一個 Linux 核心工具,其作用在於通知底層虛擬化儲存控制器釋放未使用的磁碟區塊(TRIM / Discard)。這一步相當於把黑板上不再需要的筆跡徹底擦除,讓外部的 Windows 能辨識出哪些空間是真正的空白區域:
|
|
執行後終端機應會印出類似 / : xxx GiB trimmed 的訊息,代表系統已成功向虛擬化層完成區塊標記。

第二階段:Windows 端安全關閉與 diskpart 實體收縮
在 Linux 內部標記好空白區塊之後,就可以回到 Windows 端執行真正的實體瘦身。
在開始之前,必須先理清一個重要觀念:虛擬磁碟在有人使用時是無法壓縮的。只要背景還有 Docker Desktop 或 WSL 核心行程在存取,Windows 就會對該檔案進行排他鎖定。
1. 先完全結束 Docker Desktop,再下達關閉指令
很多人的習慣是直接按右上角 X 關閉終端機或 Docker 視窗,但其實背景的常駐行程依然處於運作狀態。
建議遵循以下順序關閉:
- 到 Windows 右下角系統匣找到 Docker 鯨魚圖示,點擊右鍵選擇 Quit Docker Desktop 完全結束。
- 開啟 PowerShell 或 Windows Terminal,下達指令徹底停止 WSL 執行個體:
1wsl --shutdown - 接著輸入檢查指令,確保所有項目的
STATE都已經明確顯示為Stopped:1wsl -l -v
2. 快速找出正在吃空間的虛擬磁碟檔案(拒絕低效全硬碟掃描)
許多教學會建議使用 PowerShell 的 Get-ChildItem -Recurse 去地毯式搜尋,但因為 %LOCALAPPDATA% 目錄下塞滿了瀏覽器快取、應用程式暫存等數十萬個瑣碎檔案,遞迴掃描硬碟效率極低且會造成嚴重的磁碟讀取負擔。
其實我們完全不需要盲目搜尋,請根據你的主要使用情境直接鎖定:
情境 A:Docker Desktop 使用者(真正吃掉 200GB 的主力)
在較新版本的 Docker Desktop 中,資料磁碟的檔案名稱不是 ext4.vhdx,而是 docker_data.vhdx!它的預設存放路徑非常固定,直接複製貼上檔案總管網址列即可抵達:
|
|
小提示: 較舊版本的 Docker Desktop 則位於
%LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx。另外也可以直接開啟 Docker Desktop,點擊右上角齒輪「Settings」->「Resources」->「Advanced」,介面上的「Disk image location」欄位會直接標明精確位置。

情境 B:一般 WSL 發行版使用者(如 Ubuntu、Debian)
若使用的是純 Linux 發行版,檔案名稱才是 ext4.vhdx。要找出它在哪個資料夾,最推薦直接讀取 Windows 登錄檔(0.05 秒瞬間列出,零磁碟 I/O 負擔):
|
|
執行後系統會瞬間印出每個發行版對應的 BasePath,該路徑底下的 ext4.vhdx 就是目標檔案。
快捷替代方案:使用 Everything 秒搜
若電腦中有安裝 Everything 等檔案檢索工具,直接搜尋 docker_data.vhdx 或 *.vhdx,利用 NTFS 的 USN 日誌同樣能在 0.01 秒內精確定位。
3. 以系統管理員身分使用 diskpart 進行壓縮
diskpart 是 Windows 原生內建的命令列磁碟分區與虛擬磁碟管理工具,不需安裝任何額外軟體。
以開啟 PowerShell 或 CMD,輸入 diskpart 進入互動模式(此處會彈出以系統管理員身分執行的視窗,點是即可):

然後依序輸入以下指令:
|
|

實戰踩坑:遇到「程序無法存取檔案」怎麼辦?
在上面的實測截圖中,可以看見一個非常真實的插曲:在第一次輸入 attach vdisk readonly 時,系統跳出了以下錯誤訊息:
Diskpart 發生錯誤: 程序無法存取檔案,因為檔案正由另一個程序使用。如需詳細資訊,請參閱系統事件記錄檔。
這並不是指令有問題,而是因為剛剛關閉 Docker Desktop 時,背景的服務行程還在進行最後的寫入與收尾,檔案鎖定尚未完全釋放。
排查對策: 遇到這種情況無須慌張,只需稍候 5 到 10 秒鐘,確認 wsl -l -v 狀態確實全為 Stopped,再次輸入 attach vdisk readonly,系統就能順利以唯讀模式掛載並執行 100% 壓縮!
戰果驗收:找回 186GB 寶貴空間
壓縮完成並下達 detach vdisk 退出後,重新開啟檔案總管確認本機磁碟 (C:) 的剩餘空間:

實測磁碟空間對比:
- 瘦身前: 剩餘 104 GB / 952 GB
- 瘦身後: 剩餘 290 GB / 952 GB
- 實際回收空間: 高達 186 GB!
原本被虛擬磁碟死死霸佔的近 200 GB 空間,瞬間全數釋放回到 Windows 宿主機中,C 槽的紅色警報立刻解除。
延伸探討:這套壓縮方法能用在其他的虛擬磁碟上嗎?
答案是:完全可以!
Windows 內建的 diskpart 與底層虛擬化驅動是系統級的通用功能。只要符合以下兩大條件,任何虛擬磁碟都能通用這套壓縮機制:
- 檔案格式為
.vhd或.vhdx。 - 磁碟類型為「動態擴充(Dynamically Expanding)」。若是「固定大小(Fixed Size)」磁碟,因空間在建立時已全部鎖定,無法透過 compact 進行物理收縮。
常見虛擬化環境適用清單
| 應用情境 | 虛擬磁碟格式 | 壓縮可行性 | 操作關鍵說明 |
|---|---|---|---|
| WSL 2 各 Linux 發行版 | ext4.vhdx |
完全適用 | 需先於 Linux 執行 fstrim -v /,執行 wsl --shutdown 後壓縮 |
| Docker Desktop WSL 資料層 | docker_data.vhdx (舊版為 ext4.vhdx) |
完全適用 | 預設存放於 %LOCALAPPDATA%\Docker\wsl\disk\,需先完全結束 Docker Desktop |
| Hyper-V 虛擬機器 (Linux Guest) | .vhdx |
完全適用 | 虛擬機內部執行 fstrim -v / 後正常關機,再對該 VHDX 執行 compact |
| Hyper-V 虛擬機器 (Windows Guest) | .vhdx |
完全適用 | 內部執行「重組並最佳化磁碟機 (TRIM)」或以 sdelete -z 填零,關機後壓縮 |
| Windows Sandbox(沙盒環境) | Base VHDX | 適用 | 動態差分虛擬硬碟架構,同樣支援離線收縮 |
| VirtualBox / VMware | .vdi / .vmdk |
無法直接使用 | 需先轉檔為 .vhd/.vhdx,或改用各自原生工具(如 VBoxManage modifymedium --compact) |
虛擬磁碟壓縮通用兩大原則
- 虛擬機必須徹底離線(關機狀態): 絕不能在虛擬機器處於運作中或「已儲存狀態 (Saved State)」時進行壓縮,否則極易導致檔案系統損毀。
- Guest OS 內部必須先完成「標記」或「填零」:
- Linux: 使用
fstrim -v /。 - Windows: 使用微軟官方 Sysinternals 的
sdelete -z C:將未使用空間寫入零值,使外部壓縮引擎得以識別多餘磁區。
- Linux: 使用
延伸閱讀
如果你在 Windows 執行 PowerShell 指令時遇到指令碼安全性限制,可參考站內相關文章:
讀者互動
定期清理虛擬磁碟是維持 Windows 系統高效運作的好習慣。
- 你的 WSL 2 或 Docker 目前佔用了多少 C 槽空間?
- 依照本篇步驟操作後,你成功找回了多少 GB 的硬碟容量? 歡迎在下方留言分享你的瘦身成果與維護心得!