如果你在 WSL2 里跑 Ubuntu 22.04,大概率遇到过或者即将遇到这个场景:在 bash 里敲下 rm -rf 删掉几十 GB 的日志、Docker 镜像和缓存,回到 Windows 资源管理器一看,C 盘可用空间不仅没涨,反而又少了点。第一次遇到这事,我还以为是回收站或者系统还原在搞鬼,查了一圈才发现,问题出在 WSL2 的虚拟磁盘文件 ext4.vhdx 上——它只会在需要时变大,删除文件后并不会自动收缩。这篇文章我就把完整的压缩思路和实操步骤写下来,从 vhdx 的原理到 diskpart 压缩,再到 Docker Desktop 干扰、稀疏虚拟磁盘这些坑,一次讲透。适合刚接触 WSL2 的新手,也适合在 C 盘告急边缘挣扎的老用户。
1. 先搞清楚空间去哪了:vhdx 只涨不缩的文件系统真相
1.1 动态扩展磁盘:只负责长大,不负责瘦身
WSL2 不是传统意义上的 Linux 虚拟机,它实际跑在一个轻量级 Hyper-V 虚拟机里。Ubuntu 22.04 的整个文件系统被封装在一个虚拟磁盘文件 ext4.vhdx 中,默认放在 Windows 用户目录下。WSL2 创建这个文件时采用“动态扩展”模式,什么意思呢?就是一开始它可能只有几 GB,随着你往里面装软件、拉 Docker 镜像、编译代码,文件会慢慢向外扩张,直到到达 256GB 的上限。
问题恰恰出在“动态扩展”只有扩张机制,没有自动收缩机制。你在 Ubuntu 里删除文件时,Linux 的 ext4 文件系统只是把这些数据块标记为“空闲”,并不会主动把底层虚拟磁盘里的区域清空,也不会告诉 Hyper-V“这里可以释放了”。于是 ext4.vhdx 这个文件在 Windows 眼里始终保持着历史最高水位。哪怕你删了 100GB 数据,它的体积依然纹丝不动,甚至因为删除操作产生的新元数据,还会不降反升。
打个比方:vhdx 就像带隔间的仓库,货物运走之后隔间骨架还在,仓库占地不会因为少了几件货就自动变小。只有管理员走进来把空隔间拆掉,仓库才会恢复原状。在 WSL2 里,这个“拆隔间”的动作就叫压缩虚拟磁盘。
1.2 三个“大小”对不上是正常的:used、du、vhdx
判断要不要压缩、能压缩回多少,首先得区分三个概念:
| 指标 | 来源 | 描述 |
|---|---|---|
df -h / 的 Used |
WSL 内部 | 文件系统认为当前实际占用的空间 |
du -sh |
WSL 内部 | 某个路径下真实文件的总大小 |
ext4.vhdx 文件大小 |
Windows 资源管理器 | 宿主机视角下虚拟磁盘文件体积 |
这三者本来就对不上。我手头这台 Windows 11 + Ubuntu 22.04,长期用 Docker 构建镜像,df 显示 Used 只有 48GB,但 ext4.vhdx 已经长到 163GB。中间差的 115GB 全是历史幽灵数据,不压缩的话,Windows 会一直把这 115GB 当成已占用空间,C 盘可用空间自然越来越少。
所以压缩前的核心判断逻辑就是一句话:vhdx 文件大小减去df 里的实际 Used,差值越大,压缩收益越高。如果差值只有两三 GB,就别折腾了。
1.3 删除文件只是第一步,fstrim 才是关键
很多人压缩失败或者压缩后空间没变化,原因就是漏了一个动作:fstrim。
删除文件本身只是把块标记为“空闲”,Hyper-V 底层并不知道哪些块可以回收。fstrim 的作用是扫描文件系统里的空闲块,并向虚拟磁盘发送 TRIM/UNMAP 指令,告诉底层“这些区域已经没用了,可以释放”。做了这一步,后面的压缩才有空间可收。
bash复制sudo fstrim -av
这命令会把所有已挂载文件系统都执行一遍 TRIM。在 WSL2 里,这步做得越彻底,后面压缩效果越好。如果跳过,直接去 diskpart compact,运气好能回收一点,运气不好可能一点变化都没有。
注意:fstrim 不是 Windows 的回收站清空,它只负责给底层“报空”,真正的空间回收还得靠下一步的虚拟磁盘压缩操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 压缩前的容量清理与可回收空间估算
2.1 先找出吃空间的大户,别上来就压缩
如果你直接压缩一个装满垃圾数据的 vhdx,效果会非常有限。压缩的本质是把空洞释放出来,而空洞源于被删除的文件。你都没删东西,自然没洞可收。所以正确顺序是:先清理真实垃圾,再 fstrim,最后压缩。
在 Ubuntu 22.04 里,按我的经验,空间大户基本按这个顺序排列:
- Docker:`/var/l
