不管是刚接触 Linux 的新手,还是已经在生产环境里摸爬滚打多年的运维,日常都会遇到几个"说大不大、说小不小"的别扭问题:明明删了文件,磁盘空间却不见少;从 Windows 那边拷过来的压缩包一解压全是乱码;外接显示器插上之后黑屏没反应;新建的用户怎么都配不对 sudo 权限。这些问题的共同点是,网上搜出来的答案往往只给一个命令,不讲为什么,换个环境就失灵。这篇内容我不打算再罗列"Linux 常用 100 个命令"那种清单,而是挑几个高频出现、又确实容易卡壳的真实场景,把背后的原理和完整的排查思路拆开讲清楚。无论你用的是虚拟机里的 Ubuntu、物理机上的 CentOS,还是 Windows 下的 WSL,这几套思路基本都能直接套用。
1. WSL 里删除文件后磁盘空间没释放:虚拟磁盘的"只进不出"
如果你在 WSL 里用 rm 删掉几个大文件,回到 Windows 一看,C 盘可用空间一点没变多,别急着怀疑人生,这属于 WSL 的常见表现,不是删除失败。
1.1 问题根源:ext4.vhdx 只增长不收缩
WSL 1 和 WSL 2 的磁盘存储机制不一样。WSL 2 跑在轻量级虚拟机里,整个 Linux 文件系统被打包进一个虚拟磁盘文件,默认位置在:
code复制C:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_xxxx\LocalState\ext4.vhdx
这个 ext4.vhdx 的本质是一个动态扩展的虚拟硬盘。你在 WSL 里写文件时,它会像气球一样逐渐变大;但当你删除 WSL 内部的文件时,这个虚拟磁盘文件并不会自动缩小。这就好比一个箱子装满了东西,你把东西拿出去了,箱子本身并不会自己变小,除非你手动把它压扁。
所以排查的第一步不是去看 Windows 的资源管理器,而是在 WSL 内部确认数据是否真的删干净了:
bash复制# 查看当前磁盘占用情况
df -h /
# 找出占用空间的大目录,按从大到小排列
sudo du -x -h --max-depth=1 / 2>/dev/null | sort -hr | head -20
df -h 看到的是文件系统层面的使用率,如果这里显示的 Avail 空间已经变大,说明文件确实删掉了,剩下的事情就是怎么让虚拟磁盘文件也瘦身。
1.2 解决方案:从 WSL 外部压缩虚拟磁盘
给 ext4.vhdx 瘦身最有效的方法是先彻底关闭 WSL,再用 Windows 自带的磁盘工具去压缩虚拟磁盘文件。
第一步,在 PowerShell(管理员模式)里完整关闭 WSL:
powershell复制wsl --shutdown
注意,wsl --shutdown 会把所有正在运行的 WSL 发行版全部关停。执行完这条命令后,建议等几秒钟,确保 Vmmem 和 VmmemWSL 进程真正退出。
第二步,用 diskpart 压缩虚拟磁盘。打开一个新的 PowerShell(管理员)窗口,依次执行:
powershell复制diskpart
select vdisk file="C:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_xxxx\LocalState\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
attach vdisk readonly 这一步很关键,它把虚拟磁盘以只读方式挂载,避免压缩过程中产生新的写入。compact vdisk 会扫描虚拟磁盘里未使用的空间并释放掉,压缩完成后 detach vdisk 解除挂载。
第三步,重新进入 WSL,确认 / 的可用空间正常,同时回到 Windows 看 C 盘空间是否回升。实测下来,删掉几十 GB 的构建缓存后,压缩完 ext4.vhdx 基本能瘦回和真实使用量接近的大小。
1.3 后续如何避免再被这个问题坑
既然知道了 WSL 的虚拟磁盘"只进不出",平时使用时就该养成几个习惯:
- 大文件、编译中间产物、Docker 镜像缓存尽量放到
/tmp或者一个固定目录,确认不需要了尽快清掉,不要堆积。 - 用
wsl --manage <发行版名> --set-sparse true将磁盘设为稀疏模式。稀疏模式的虚拟磁盘在 Linux 内删除文件后,空间会更容易归还给 Windows,不用每次手动 compact。 - 不要频繁在 WSL 和 Windows 之间拷贝超大文件,跨文件系统的读写开销远高于同一文件系统内部的操作。
code复制wsl --manage Ubuntu --set-sparse true
要注意,--set-sparse true 需要较新版本的 WSL,如果提示命令不存在,先运行 `wsl --update
