跳至主要內容

WSL 2 與 Docker 虛擬磁碟瘦身指南:用 diskpart 徹底釋放 C 槽空間

在 Windows 頻繁使用 WSL 2 與 Docker 導致 C 槽空間告急?本文完整記錄透過內部清理、fstrim 標記未用區塊與原生 diskpart 工具成功回收 186GB 空間的實戰全流程,並附上常見檔案鎖定排查與其他虛擬磁碟適用性解析。

The Walking Fish 步行魚
The Walking Fish 步行魚 ·
3877 字 · 閱讀時間: 9 分鐘 · ...
WSL 2 與 Docker 虛擬磁碟瘦身指南:用 diskpart 徹底釋放 C 槽空間
Fig. 01 — WSL 2 與 Docker 虛擬磁碟瘦身指南:用 diskpart … FEATURED IMAGE

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 槽剩餘空間告急,僅剩 104 GB 可用容量

這是我前陣子的親身經歷:我的 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) 機制:

  1. 按需索取空間: 當你在 Linux 中下載套件、建構 Docker 映像檔或寫入大量檔案時,底層驅動會向 Windows 宿主機即時索取實體儲存空間,檔案體積因而持續膨脹。
  2. 刪除不主動回縮: 當你在 Linux 內部刪除檔案時,Linux 核心僅是將對應的磁區標記為「空閒區塊(Free Blocks)」。宿主機的 Windows 檔案系統並無法得知虛擬磁碟內部哪些資料已經無效,因此 VHDX 的實體大小不會自動縮減。

要真正回收空間,必須在內部先清理無效資料並標記區塊,然後在外部將虛擬磁碟進行實體壓縮與釋放。


第一階段:Linux 與 Docker 內部大掃除與區塊標記

1. 清理 Docker 映像檔、容器與建構快取

啟動 CMD (Windows 終端機),執行以下指令清理 Docker 累積的龐大資料:

1
2
3
4
5
# 1. 清理 BuildKit 建構快取(頻繁 docker build 的主要膨脹來源)
docker builder prune -a -f

# 2. 清理所有未被使用的容器、網路與未標記映像檔
docker system prune -a --volumes -f

重要提醒: docker system prune -a --volumes 會清除所有已停止運作的容器、未被引用的映像檔以及未命名的匿名磁碟區 (Anonymous Volumes)。如果容器內有重要資料庫檔案,請務必先確認資料已掛載於具名磁碟區 (Named Volume) 或有完整備份。

2. 清理 Linux 系統快取

接著我們要進到 wsl 內,清理 Linux 套件管理器與日常開發工具累積的快取檔案:

此步驟主要是 WSL 使用,如果是只有 docker 的話就不用做了

先使用 wsl -d <發行版> 的指令進入 wsl 的終端機,例如:

1
wsl -d Ubuntu

然後執行以下指令清理 APT 套件快取與不再需要的孤立套件:

1
2
3
4
5
6
7
8
9
# 清理 APT 套件快取與不再需要的孤立套件
sudo apt-get clean
sudo apt-get autoclean
sudo apt-get autoremove -y

# 若有在 WSL 內部進行各語言開發,可選擇性清理快取
npm cache clean --force 2>/dev/null
yarn cache clean 2>/dev/null
rm -rf ~/.cargo/registry/cache/* 2>/dev/null

3. 執行 fstrim 標記未使用區塊

fstrim 是一個 Linux 核心工具,其作用在於通知底層虛擬化儲存控制器釋放未使用的磁碟區塊(TRIM / Discard)。這一步相當於把黑板上不再需要的筆跡徹底擦除,讓外部的 Windows 能辨識出哪些空間是真正的空白區域:

1
sudo fstrim -v /

執行後終端機應會印出類似 / : xxx GiB trimmed 的訊息,代表系統已成功向虛擬化層完成區塊標記。

執行完後的訊息顯示


第二階段:Windows 端安全關閉與 diskpart 實體收縮

在 Linux 內部標記好空白區塊之後,就可以回到 Windows 端執行真正的實體瘦身。

在開始之前,必須先理清一個重要觀念:虛擬磁碟在有人使用時是無法壓縮的。只要背景還有 Docker Desktop 或 WSL 核心行程在存取,Windows 就會對該檔案進行排他鎖定。

1. 先完全結束 Docker Desktop,再下達關閉指令

很多人的習慣是直接按右上角 X 關閉終端機或 Docker 視窗,但其實背景的常駐行程依然處於運作狀態。

建議遵循以下順序關閉:

  1. 到 Windows 右下角系統匣找到 Docker 鯨魚圖示,點擊右鍵選擇 Quit Docker Desktop 完全結束。
  2. 開啟 PowerShell 或 Windows Terminal,下達指令徹底停止 WSL 執行個體:
    1
    
    wsl --shutdown
    
  3. 接著輸入檢查指令,確保所有項目的 STATE 都已經明確顯示為 Stopped:
    1
    
    wsl -l -v
    

2. 快速找出正在吃空間的虛擬磁碟檔案(拒絕低效全硬碟掃描)

許多教學會建議使用 PowerShell 的 Get-ChildItem -Recurse 去地毯式搜尋,但因為 %LOCALAPPDATA% 目錄下塞滿了瀏覽器快取、應用程式暫存等數十萬個瑣碎檔案,遞迴掃描硬碟效率極低且會造成嚴重的磁碟讀取負擔。

其實我們完全不需要盲目搜尋,請根據你的主要使用情境直接鎖定:

情境 A:Docker Desktop 使用者(真正吃掉 200GB 的主力)

在較新版本的 Docker Desktop 中,資料磁碟的檔案名稱不是 ext4.vhdx,而是 docker_data.vhdx!它的預設存放路徑非常固定,直接複製貼上檔案總管網址列即可抵達:

1
%LOCALAPPDATA%\Docker\wsl\disk\docker_data.vhdx

小提示: 較舊版本的 Docker Desktop 則位於 %LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx。另外也可以直接開啟 Docker Desktop,點擊右上角齒輪「Settings」->「Resources」->「Advanced」,介面上的「Disk image location」欄位會直接標明精確位置。

Docker Desktop 的設定中可查看虛擬磁碟實際存放位置

情境 B:一般 WSL 發行版使用者(如 Ubuntu、Debian)

若使用的是純 Linux 發行版,檔案名稱才是 ext4.vhdx。要找出它在哪個資料夾,最推薦直接讀取 Windows 登錄檔(0.05 秒瞬間列出,零磁碟 I/O 負擔):

1
Get-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss\* | Select-Object DistributionName, BasePath

執行後系統會瞬間印出每個發行版對應的 BasePath,該路徑底下的 ext4.vhdx 就是目標檔案。

快捷替代方案:使用 Everything 秒搜

若電腦中有安裝 Everything 等檔案檢索工具,直接搜尋 docker_data.vhdx 或 *.vhdx,利用 NTFS 的 USN 日誌同樣能在 0.01 秒內精確定位。

3. 以系統管理員身分使用 diskpart 進行壓縮

diskpart 是 Windows 原生內建的命令列磁碟分區與虛擬磁碟管理工具,不需安裝任何額外軟體。

以開啟 PowerShell 或 CMD,輸入 diskpart 進入互動模式(此處會彈出以系統管理員身分執行的視窗,點是即可):

在 PowerShell 輸入 diskpart 啟動工具

然後依序輸入以下指令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 1. 選取目標虛擬磁碟(以 Docker Desktop 為例,請將路徑替換為你實際的檔案路徑)
select vdisk file="C:\Users\YOUR_USERNAME\AppData\Local\Docker\wsl\disk\docker_data.vhdx"

# 若是要壓縮一般 Ubuntu 發行版,則指定對應的 ext4.vhdx 路徑:
# select vdisk file="C:\Users\YOUR_USERNAME\...\ext4.vhdx"

# 2. 以唯讀模式掛載
attach vdisk readonly

# 3. 執行物理收縮
compact vdisk

# 4. 卸載虛擬磁碟並離開
detach vdisk
exit

diskpart 壓縮執行過程,包含鎖定錯誤排查與成功壓縮畫面

實戰踩坑:遇到「程序無法存取檔案」怎麼辦?

在上面的實測截圖中,可以看見一個非常真實的插曲:在第一次輸入 attach vdisk readonly 時,系統跳出了以下錯誤訊息:

Diskpart 發生錯誤: 程序無法存取檔案,因為檔案正由另一個程序使用。如需詳細資訊,請參閱系統事件記錄檔。

這並不是指令有問題,而是因為剛剛關閉 Docker Desktop 時,背景的服務行程還在進行最後的寫入與收尾,檔案鎖定尚未完全釋放。

排查對策: 遇到這種情況無須慌張,只需稍候 5 到 10 秒鐘,確認 wsl -l -v 狀態確實全為 Stopped,再次輸入 attach vdisk readonly,系統就能順利以唯讀模式掛載並執行 100% 壓縮!


戰果驗收:找回 186GB 寶貴空間

壓縮完成並下達 detach vdisk 退出後,重新開啟檔案總管確認本機磁碟 (C:) 的剩餘空間:

C 槽可用空間從 104 GB 恢復至 290 GB,磁碟條回到健康的藍色狀態

實測磁碟空間對比:

  • 瘦身前: 剩餘 104 GB / 952 GB
  • 瘦身後: 剩餘 290 GB / 952 GB
  • 實際回收空間: 高達 186 GB!

原本被虛擬磁碟死死霸佔的近 200 GB 空間,瞬間全數釋放回到 Windows 宿主機中,C 槽的紅色警報立刻解除。


延伸探討:這套壓縮方法能用在其他的虛擬磁碟上嗎?

答案是:完全可以!

Windows 內建的 diskpart 與底層虛擬化驅動是系統級的通用功能。只要符合以下兩大條件,任何虛擬磁碟都能通用這套壓縮機制:

  1. 檔案格式為 .vhd 或 .vhdx。
  2. 磁碟類型為「動態擴充(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)

虛擬磁碟壓縮通用兩大原則

  1. 虛擬機必須徹底離線(關機狀態): 絕不能在虛擬機器處於運作中或「已儲存狀態 (Saved State)」時進行壓縮,否則極易導致檔案系統損毀。
  2. Guest OS 內部必須先完成「標記」或「填零」:
    • Linux: 使用 fstrim -v /。
    • Windows: 使用微軟官方 Sysinternals 的 sdelete -z C: 將未使用空間寫入零值,使外部壓縮引擎得以識別多餘磁區。

延伸閱讀

如果你在 Windows 執行 PowerShell 指令時遇到指令碼安全性限制,可參考站內相關文章:


讀者互動

定期清理虛擬磁碟是維持 Windows 系統高效運作的好習慣。

  • 你的 WSL 2 或 Docker 目前佔用了多少 C 槽空間?
  • 依照本篇步驟操作後,你成功找回了多少 GB 的硬碟容量? 歡迎在下方留言分享你的瘦身成果與維護心得!
SHARE / 分享此文章