跳至内容
WSL2 实际只用 40G,为什么 Windows 上却占了 256G?

WSL2 实际只用 40G,为什么 Windows 上却占了 256G?

2026-10-30

Linux 里 df -h 显示只用了 40G,Windows 上的 ext4.vhdx 却占了 256G。这个差异很常见,原因是 WSL2 的虚拟磁盘只会自动变大,不会因为删文件就自动变小。下面记录几种回收空间的方法。

问题的现象

先看一个例子:

$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb        1.0T   40G  960G   4% /

Linux 里明明只用了 40G,但打开 Windows 的资源管理器或者 Get-ChildItem 一看,ext4.vhdx 这个文件已经膨胀到了 256G。

df 统计的是文件系统当前使用了多少空间,Windows 看到的则是 vhdx 文件已经扩展到多大,两者不是一回事。

原因:虚拟磁盘只增不减

WSL2 并不是把文件直接写在 Windows 的 NTFS 上,而是用一块 ext4 格式的虚拟硬盘(VHDX)来承载整个 Linux 根文件系统。这块虚拟磁盘在 Windows 上就是一个普通的 ext4.vhdx 文件。

它大致是这样工作的:

  • 按需增长:你在 Linux 里写入数据,vhdx 文件跟着变大;
  • 不会自动收缩:你删掉 Linux 里的文件,ext4 只是把对应的块标记为“空闲”,vhdx 文件本身纹丝不动;
  • 上限很高:新版 WSL 的虚拟磁盘上限可以达到 1TB(更早的版本通常是 512GB 或 256GB),所以 df -h 里显示的 Size 很大,并不代表真的占用了这么多空间。

所以,40G 是当前文件系统里的数据量,256G 则是 vhdx 曾经扩展到的大小。

Docker Desktop 也经常占掉很大一块空间。它会单独使用一个虚拟磁盘(新版一般是 %LOCALAPPDATA%\Docker\wsl\disk\docker_data.vhdx,旧版是 %LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx)。可以先把所有 vhdx 找出来,看看究竟是谁占空间:

Get-ChildItem -Path $env:LOCALAPPDATA -Recurse -Filter *.vhdx -ErrorAction SilentlyContinue |
  Select-Object FullName, @{N='SizeGB';E={[math]::Round($_.Length/1GB,1)}}

这段脚本只扫描 %LOCALAPPDATA%。如果你曾用 wsl --import 或迁移工具把发行版放到了其他目录,需要到对应目录下自行查看。

方案一:稀疏 VHD(目前官方已禁用)

理想情况下,可以开启稀疏 VHD(sparse VHD)。这样 vhdx 删除数据后有机会把空间还给 Windows,不需要每次手动压缩。

wsl --shutdown
wsl --manage <发行版名> --set-sparse true

不过现在直接执行通常会遇到下面的报错:

由于潜在的数据损坏,目前已禁用稀疏 VHD 支持。
要强制发行版使用稀疏 VHD,请运行:
wsl.exe --manage <DistributionName> --set-sparse true --allow-unsafe
错误代码: Wsl/Service/E_INVALIDARG

微软后来因为数据损坏和丢失的反馈,关闭了这个功能,只留下 --allow-unsafe 作为强制开启的选项。

不建议加 --allow-unsafe。 为了省几十 GB 空间,没必要拿整个 Linux 环境冒险。

方案二:fstrim + compact vdisk(推荐)

一般先用这个办法,分两步操作。

先在 WSL 里执行:

sudo fstrim -av

fstrim 会把 ext4 中已经空闲的块通知给虚拟磁盘。少了这一步,后面的压缩通常回收不了那么多空间。

然后关闭 WSL,用管理员权限打开命令提示符,进入 diskpart:

wsl --shutdown
diskpart
select vdisk file="C:\完整路径\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit

compact vdisk 会尝试回收未使用的块。能压回多少取决于文件系统中空闲块的分布,不一定正好回到 40G。

找到 vhdx 路径的方法:wsl --list --verbose 查看发行版名,默认安装的商店版 Ubuntu 一般在:

%LOCALAPPDATA%\Packages\CanonicalGroupLimited...\LocalState\ext4.vhdx

如果你曾经迁移过 WSL,则在自定义目录下。

方案三:Optimize-VHD(需要 Hyper-V)

如果机器上启用了 Hyper-V 功能,可以直接用 PowerShell 一条命令搞定:

wsl --shutdown
Optimize-VHD -Path "C:\完整路径\ext4.vhdx" -Mode Full

效果和 compact vdisk 类似,但依赖 Hyper-V 组件(Optimize-VHD 属于 Hyper-V PowerShell 模块)。Windows 家庭版不支持 Hyper-V,无法使用这个方法,请改用方案二。

方案四:导出再导入(压缩最彻底)

如果 compact 效果不理想,或者 vhdx 已经出现了难以处理的异常,可以用导出/导入的方式重建一个只包含实际数据的新虚拟磁盘:

wsl --shutdown
wsl --export Ubuntu D:\backup\ubuntu.tar
wsl --unregister Ubuntu
wsl --import Ubuntu D:\WSL\Ubuntu D:\backup\ubuntu.tar

新生成的 vhdx 会紧贴实际数据量,通常是最“干净”的结果。

几个注意点:

  1. 预留足够的磁盘空间:导出的 tar 大小约等于实际数据量(本例约 40G),存放 tar 的盘要有足够空间;
  2. 必须先确认 tar 导出成功(检查文件大小是否合理)再执行 --unregister,因为该命令会直接删除原 vhdx,删了就没法后悔了;
  3. 不要对 docker-desktop 发行版这样操作:Docker 的数据请用 Docker 自己的方式清理(见文末维护建议);
  4. 导入后默认登录用户会变回 root,需要在 /etc/wsl.conf 里补上:
[user]
default=你的用户名

修改后执行 wsl --terminate Ubuntu(或 wsl --shutdown),重新进入 WSL 才会生效。

踩坑:compact 时报“另一个程序正在使用此文件”

执行 compact 时经常遇到:

DiskPart 遇到错误: 另一个程序正在使用此文件,进程无法访问。

这说明 vhdx 仍被某个进程占用。按顺序排查:

1. 确认 WSL 真的完全关闭

wsl --shutdown
# 等 10~15 秒,让 vmmem 进程回收
wsl --list --running
Get-Process | Where-Object {$_.Name -like "*vmmem*"}

wsl --list --running 应该没有任何输出,vmmem / vmmemWSL 进程也应消失。

注意 wsl --shutdown 只清理当前用户会话的 WSL。如果这台机器有多个 Windows 账户,或者有系统服务在调 WSL,文件仍可能被占用。

2. 关掉 Docker Desktop 和 VS Code

  • Docker Desktop:托盘图标右键 → Quit;
  • VS Code:关闭所有 Remote-WSL 窗口,否则 wsl.exe 会驻留;
  • Windows Terminal:关掉所有相关标签页。

3. 用资源监视器揪出占用者

这个工具最直接:

  1. Win + R 输入 resmon 回车;
  2. 切到 CPU 标签,展开“关联的句柄”;
  3. 搜索框输入 ext4.vhdx;
  4. 列表里出现的进程就是元凶,正常退出它。

4. 重启电脑

有些后台软件(杀毒、备份、索引服务)会短暂锁定文件,资源监视器也未必能及时捕捉到。重启后不要打开任何 WSL 相关程序,直接以管理员身份跑 diskpart,是最省心的办法。

5. 记得 detach

如果 compact 是在 attach vdisk readonly 之后失败退出,别忘了先 detach vdisk 再关 diskpart,否则是你自己把文件锁住了。

一些长期维护建议

  • 定期执行 sudo fstrim -av 再 compact,当作月度保养;
  • Docker 用户:先用 docker system prune -a 清理无用的镜像、容器和构建缓存,清理完再压缩 Docker 的 vhdx。慎用 --volumes 参数:它会删除所有未被容器使用的数据卷,暂时停掉的数据库容器的数据也可能被一并删除;
  • 关注 sparse VHD 的修复进展:等微软解决底层数据损坏问题后,这个功能大概率会重新开放,那时候就不用再折腾了;
  • 体积大、访问少的文件别放 WSL 里:数据集、虚拟机镜像、归档备份可以放在 Windows 盘符下,通过 /mnt/d/... 访问,能显著减缓 vhdx 膨胀。但跨文件系统访问很慢,代码仓库、node_modules、编译产物这类小文件多、读写频繁的目录仍应留在 WSL 内部。

小结

方案适用场景风险
--set-sparse true已被官方禁用需 --allow-unsafe,有数据损坏风险,不推荐
fstrim + compact vdisk日常首选低
Optimize-VHD有 Hyper-V 环境低
export / importcompact 无效或 vhdx 异常中(需先备份成功)

一句话结论:WSL2 的 vhdx 只涨不跌是设计使然,df -h 和 Windows 看到的数字对不上是正常现象;最稳妥的做法是 fstrim + diskpart compact,而不是强行开启已经被禁用的稀疏 VHD。

最后更新于