场景:在 WSL2(Ubuntu-24.04)里
rm -rf删掉了约 50GB 的大文件(一个弃用的 LLM 模型),回到 Windows 一看 C 盘可用空间几乎没有变化。本文记录完整的排查过程和最终解法,涉及 fstrim、WSL 稀疏 VHD 模式、Optimize-VHD / diskpart 压缩,以及一个很容易踩的坑。
1. 现象
- WSL 内确认文件已删除:
/home/dev/models/下只剩需要的模型目录,du -sh确认大目录已消失 - 但 Windows 侧 C 盘可用空间没有回升(实测仅剩 ~22GB,几乎没有变化)
- 执行
wsl --shutdown重启后依然如此
2. 根因:WSL2 的磁盘是一块“只涨不缩”的虚拟硬盘
WSL2 不是直接使用 Windows 文件系统,而是把发行版装在一个动态扩展的虚拟硬盘(VHDX)文件里。它的工作方式:
- VHDX 文件会随使用自动增长(写入越多文件越大)
- 但删除文件只释放 VHDX 内部的逻辑空间,文件本身不会自动缩小——那些块只是被标记为“空闲”,Windows 侧的 C 盘空间依然被占用
- 只有显式执行“压缩/收缩”操作,VHDX 才会把尾部空闲块归还给 Windows
所以“WSL 里删了文件 → Windows 空间变多”是不成立的,必须主动收缩 VHDX。
3. 排查:找到 VHDX 并确认空洞
3.1 找到发行版对应的 VHDX 路径
发行版的虚拟磁盘位置存在注册表里:
Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss" |
ForEach-Object {
$p = Get-ItemProperty $_.PSPath
[PSCustomObject]@{ Distro=$p.DistributionName; BasePath=$p.BasePath }
}
我机器的结果(Windows 11 / WSL 2.7.13):
Distro : Ubuntu-24.04
BasePath : C:\Users\Dev\AppData\Local\wsl\{7681ba24-e842-452b-9fc7-1502c48565ff}
VHDX 文件就是 BasePath\ext4.vhdx。
3.2 对比“内部使用”与“文件大小”,确认空洞
WSL 内部视角(df -h /):
Filesystem Size Used Avail Use% Mounted on
/dev/sdd 1007G 165G 792G 18% /
Windows 视角(VHDX 文件大小):
VHDX: C:\Users\Dev\AppData\Local\wsl\{...}\ext4.vhdx
Size: 221.6 GB
内部只用 165G,文件却占 221.6G → 约 56GB 是“已删除但未回收”的空洞,这就是丢失空间的来源。
4. 解决方案(按推荐顺序)
方案 A:WSL 2.7+ 稀疏 VHD 模式(一劳永逸)
WSL 2.7 起支持把 VHD 转换为稀疏模式(sparse VHD):开启后,在 WSL 里删除文件会自动把空间归还给 Windows,无需再手动压缩。
# 1. 先让文件系统标记可回收块(需要 root)
wsl -d Ubuntu-24.04 -u root -- fstrim -v /
# 输出示例:/: 841 GiB (902995951616 bytes) trimmed
# 2. 关闭 WSL
wsl --shutdown
# 3. 转换为稀疏模式(必须带 --allow-unsafe)
wsl --manage Ubuntu-24.04 --set-sparse true --allow-unsafe
# 4. 验证(应显示 "This file is set as sparse")
fsutil sparse queryflag "C:\...\ext4.vhdx"
⚠️ 注意:稀疏模式对开启前已存在的空洞不自动回收(实测 fstrim + 挂载后 C 盘空间无变化)。也就是说:转换前删除的大文件,需要额外做一次压缩(见方案 B)才能释放;转换后新删除的文件才会自动回收。
方案 B:Optimize-VHD 压缩(处理存量空洞,需管理员)
先确认 WSL 已 wsl --shutdown,然后以管理员身份打开 PowerShell 执行:
Optimize-VHD -Path "C:\Users\Dev\AppData\Local\wsl\{7681ba24-e842-452b-9fc7-1502c48565ff}\ext4.vhdx" -Mode Full
预期效果:VHDX 从 221.6 GB 收缩到约 165 GB(接近内部实际使用量),一次性释放约 55 GB。
如果系统没有 Hyper-V 模块,可用 diskpart 代替(同样管理员):
diskpart
select vdisk file="C:\Users\Dev\AppData\Local\wsl\{7681ba24-e842-452b-9fc7-1502c48565ff}\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
完整流程(我的实际顺序,一次成功)
1. wsl -d Ubuntu-24.04 -u root -- fstrim -v / # 标记可回收块
2. wsl --shutdown # 关闭 WSL(释放文件句柄)
3. wsl --manage Ubuntu-24.04 --set-sparse true --allow-unsafe # 开启稀疏模式
4. Optimize-VHD ... -Mode Full # 管理员,压缩存量空洞
5. 最容易踩的坑:稀疏文件无法压缩
在我先开启了稀疏模式(方案 A)之后,管理员运行 Optimize-VHD 直接报错:
Optimize-VHD: 无法压缩虚拟磁盘。
无法打开附件"...ext4.vhdx"。错误:"由于虚拟磁盘系统限制,无法完成请求的操作。
虚拟硬盘文件必须是未压缩和未加密的文件,并且不能是稀疏文件。"
原因:稀疏 VHD 和 Optimize-VHD/diskpart 压缩是互斥的——压缩工具要求文件是非稀疏的普通动态 VHD。
解法:先转回动态模式,再压缩:
wsl --manage Ubuntu-24.04 --set-sparse false --allow-unsafe
fsutil sparse queryflag "C:\...\ext4.vhdx" # 应显示 "This file is NOT set as sparse"
# 然后管理员运行 Optimize-VHD
如果你的诉求是”一次释放存量空间“,直接走方案 B 即可,不用开稀疏模式;如果诉求是”以后删除自动释放“,开稀疏模式,但存量空洞仍需一次方案 B 压缩收尾。
6. 日常维护建议
- 优先考虑稀疏模式(WSL 2.7+):一次配置,以后删除文件自动回收空间,不用再手动压缩
- 定期压缩(非稀疏模式):删除大文件后执行
fstrim→wsl --shutdown→Optimize-VHD,可以写成一个脚本 - 监控:关注
df -h /与 VHDX 文件大小的差距,差距越大说明空洞越多 - 注意 C 盘空间:如果 C 盘可用空间本身很小(例如 <30GB),压缩前先确认有足够临时空间,并留意
set-sparse false转换时的空间需求 - 区分两种“空间”:WSL 内部
df显示的是虚拟磁盘内部分区使用;Windows 资源管理器看的是 VHDX 文件占用——两者不相等是正常的,别被吓到
7. 结论
WSL2 删除文件不释放 Windows 磁盘空间,是动态 VHDX 的正常机制而非故障。解决路径清晰:fstrim 标记 → wsl --shutdown → 开启稀疏模式或 Optimize-VHD 压缩。注意稀疏模式与压缩工具互斥,先转换再压缩即可。实测可一次性回收约 55 GB 空间。