2026年1月12日 星期一

學習雜記 - 電腦隨記 - 為什麼 docker prune 之後,Windows 磁碟空間還是不會回來?(WSL2 實測)

TL;DR

在 WSL2 裡自行安裝 Docker 的情境下:

docker prune 只會清掉 WSL 內部空間,不會讓 Windows 磁碟變大。
一定要對 ext4.vhdx 執行 compact vdisk,Windows 空間才會真的回收。

本文為實測案例,本次實際回收約 20GB


問題背景

環境條件:

  • Windows + WSL2(Ubuntu)

  • Docker 直接安裝在 WSL 裡(非 Docker Desktop)

  • 經常進行:

    • docker build

    • image / layer 測試

    • docker system prune

遇到的狀況:

  • 在 WSL 內執行:

    df -h /

    顯示磁碟使用率很低(例如只用 10%~15%)

  • 但 Windows 系統磁碟空間:

    • 完全沒有回來

    • 即使已執行 docker prune

    • 關閉 WSL、甚至重開機也無效


關鍵觀念:WSL2 的磁碟模型

WSL2 的 Linux 檔案系統,實際上是:

  • 一顆 ext4.vhdx 虛擬磁碟

  • 以單一檔案形式存在於 Windows 的 NTFS 檔案系統中

重點差異在這裡

動作實際影響
docker prune刪除 ext4 內部檔案
df -h只顯示 ext4 內部可用 block
Windows 磁碟只看到 ext4.vhdx 檔案大小

👉 ext4.vhdx 不會因為你刪檔而自動縮小

這也是為什麼你會看到一個非常反直覺的現象:

  • WSL:看起來很乾淨

  • Windows:磁碟空間完全沒變


為什麼 docker prune 沒用(這不是 bug)

docker prune 做的事情是:

  • 刪除 Docker layer、cache、container

  • 將 ext4 內的 block 標記為「可用」

但問題在於:

  • ext4.vhdx 檔案本身大小不會改變

  • Windows 只知道「這顆檔案還是這麼大」

這和 VM、Hyper-V、VHDX 的行為是一致的,
不是 Docker 的問題,也不是 WSL 的 bug,而是設計本來如此。


真正有效的解法(唯一)

Step 1:找出 WSL distro 的實際磁碟位置

WSL 的磁碟位置必須從 registry 查詢(權威來源):

Get-ChildItem HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | ForEach-Object { $p = Get-ItemProperty $_.PSPath "$($p.DistributionName) -> $($p.BasePath)" }

輸出範例(已匿名):

Ubuntu -> C:\Users\<USER>\AppData\Local\wsl\{DISTRO_GUID}

實際磁碟檔案即為:

C:\Users\<USER>\AppData\Local\wsl\{DISTRO_GUID}\ext4.vhdx

Step 2:關閉 WSL

wsl --shutdown

Step 3:對 ext4.vhdx 執行 compact(關鍵步驟)

系統管理員身分開啟 PowerShell:

diskpart

接著執行:

select vdisk file="C:\Users\<USER>\AppData\Local\wsl\{DISTRO_GUID}\ext4.vhdx" attach vdisk readonly compact vdisk detach vdisk exit

實測結果

  • Windows 磁碟空間 立刻回收

  • 本案例回收約 20GB

  • WSL 內 df -h 不會有明顯變化(本來就已清空)


一句話總結(工程師版)

在 WSL2 裡:
docker prune 只是「掃地」
compact vdisk 才是「垃圾車來把垃圾載走」


實務建議

  • docker prune:日常清理即可

  • compact vdisk

    • 不需頻繁執行

    • 大量 Docker build / cache 清理後做一次即可

    • 半年~一年一次非常足夠


註記

本文問題定位、除錯流程與最終解法
由作者實際操作驗證,並在 ChatGPT 協助分析與整理下完成