1. 虚拟机磁盘为什么会越用越大
用 VMware Workstation 的人基本都会碰到同一个问题:虚拟机用着用着,宿主机上的那个文件夹就膨胀到几十个 G,明明虚拟机里删了一堆东西,宿主机上的 vmdk 文件却一点没变小。我自己的主力开发机上有三台虚拟机,一台 Ubuntu 做编译环境,一台 Windows 10 跑一些只能在 Windows 下用的工具,还有一台 CentOS 做服务端测试,三台加起来占了快 200G,其中至少有一半是"虚胖"。
这个"虚胖"的根源在于 VMware 的磁盘分配机制。创建虚拟机时通常有两种磁盘模式:厚置备(Thick Provision)和薄置备(Thin Provision)。Workstation 里对应的是"立即分配所有磁盘空间"和"拆分成多个文件"这两个选项。如果你当初勾了"立即分配",那 vmdk 从创建那一刻起就是固定大小,删文件不会让它缩小;如果没勾,vmdk 会随着写入数据逐步增长,但增长容易收缩难——虚拟机内部删除文件后,操作系统只是把对应的块标记为"可用",VMware 并不知道这些块已经没用了,所以 vmdk 只增不减。
这就引出了清理磁盘的两条主线:一是在虚拟机内部把无用数据真正清掉,二是让 VMware 知道哪些块可以回收,从而压缩 vmdk 文件。很多人只做了第一步,发现宿主机空间没变化,就以为清理失败了,其实是漏了第二步。下面我把整套流程拆开讲,从原理到命令到踩坑,尽量让你一次搞定。
提示:本文所有操作以 VMware Workstation Pro 17 为例,宿主机为 Windows,客户机涵盖 Ubuntu、CentOS、Windows 10。ESXi 环境思路一致,但部分命令和界面不同,我会在对应位置标注。
2. 清理前的准备工作与风险认知
2.1 先搞清楚你的磁盘是哪种模式
动手之前必须先确认磁盘类型,否则后面做的压缩可能完全无效。在 VMware Workstation 里选中虚拟机,右键"设置",找到硬盘,看右侧的"磁盘实用工具"或者直接看虚拟机目录下的文件。
判断方法很简单:
- 如果目录下只有一个大的
.vmdk文件,且大小固定不变,那是厚置备单文件。 - 如果有
xxx.vmdk加上一堆xxx-s001.vmdk、xxx-s002.vmdk这样的分片文件,那是拆分模式,通常也是薄置备。 - 如果只有一个
.vmdk且会随使用增长,那是薄置备单文件。
我一般推荐薄置备,因为省空间,但代价就是需要定期清理。厚置备的好处是性能稳定、不会碎片化,但空间一旦分配就收不回来,除非用后面的方法转换。
2.2 快照是磁盘膨胀的头号元凶
在讲清理之前,必须先说快照。快照会让磁盘空间成倍增长,因为每个快照都会保存一份差异磁盘(delta disk),你后续的所有写入都记录在差异盘里,原来的基础盘保持不变。如果你有多个快照,差异盘会层层叠加,空间占用非常夸张。
我见过最极端的案例:一台 40G 的虚拟机,因为累积了 7 个快照,实际占用 180G。所以清理磁盘的第一步,永远是检查并清理快照。
在 VMware Workstation 里,菜单栏"虚拟机" → "快照" → "快照管理器",能看到所有快照的时间线。如果这些快照你都不需要了,直接删除。注意:删除快照不是删除虚拟机当前状态,而是把快照里的数据合并回基础盘,这个过程可能比较慢,取决于差异盘大小,别中途强制关闭。
注意:删除快照时如果提示空间不足,先确保宿主机有足够剩余空间,因为合并过程需要临时空间。合并完成后,虚拟机目录下那些
-000001.vmdk之类的差异盘会消失,空间会释放一部分。
2.3 备份永远不嫌多
任何涉及磁盘的操作都有风险,尤其是后面的vmware-vdiskmanager压缩和磁盘碎片整理。我的习惯是:清理前先把整个虚拟机目录复制一份到移动硬盘或者另一块盘。虚拟机目录通常就是那几个文件:.vmx(配置文件)、.vmdk(磁盘)、.nvram、.vmsd等。整个文件夹拷走,出问题直接换回来,比任何修复都靠谱。
如果你嫌整个拷贝太占空间,至少把.vmx和.vmsd备份一下,这两个文件很小,但记录了虚拟机的硬件配置,万一磁盘操作把配置搞乱了,还能对照恢复。
3. 虚拟机内部清理:把垃圾真正清掉
3.1 Linux 客户机的清理要点
Linux 下清理磁盘,核心是找出大文件和无用缓存。我常用的组合是du、find和包管理器自带的清理命令。
先看整体占用:
df -h du -sh /* 2>/dev/null | sort -rh | head -20第一条看各分区使用率,第二条列出根目录下各一级目录的大小并排序。通常/var、/usr、/home、/tmp是重灾区。
/var下面最常见的是日志和包缓存:
# 查看日志占用 du -sh /var/log/* # 清理 systemd journal 日志,只保留最近 3 天 journalctl --vacuum-time=3d # 清理 apt 缓存(Ubuntu/Debian) apt-get clean apt-get autoclean # 清理 yum/dnf 缓存(CentOS/RHEL) yum clean all dnf clean all/tmp目录可以直接清空,但注意有些程序运行时会用临时文件,最好在关机前清理:
rm -rf /tmp/*还有一个容易被忽略的地方是旧内核。Ubuntu 上每次内核更新都会保留旧版本,时间长了/boot和/usr/src会堆积很多。查看已安装内核:
dpkg --list | grep linux-image确认当前运行的内核版本(uname -r),然后删掉不用的旧内核:
apt-get purge linux-image-5.15.0-xx-genericCentOS 上用package-cleanup --oldkernels --count=2保留最近两个内核。
3.2 Windows 客户机的清理要点
Windows 虚拟机的空间大头通常是:系统更新缓存、休眠文件、页面文件、临时文件、旧系统备份。
最直接的是用系统自带的磁盘清理:右键 C 盘 → 属性 → 磁盘清理 → 清理系统文件。勾选"Windows 更新清理"、"以前的 Windows 安装"、"临时文件"等。这一步能释放几个 G 到几十个 G 不等。
休眠文件hiberfil.sys往往和内存一样大,如果虚拟机不需要休眠功能,直接关掉:
powercfg -h off页面文件pagefile.sys也可以调整,但建议保留,只是可以设小一点或者移到别的盘。如果虚拟机内存是 8G,页面文件默认可能也是 8G 左右。
另外 Windows 的WinSxS目录会随着更新越来越大,可以用:
Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase这个命令会清理组件存储里的旧版本,但执行后无法卸载已安装的更新,权衡一下再用。
3.3 用零填充把空闲块标记出来
这是最关键的一步,也是最多人漏掉的一步。虚拟机内部删除文件后,那些块在文件系统层面是空闲的,但 VMware 不知道。我们需要用零写满所有空闲空间,这样 VMware 在压缩时就能识别出这些块是"全零",从而安全回收。
Linux 下用dd或者zerofree:
# 方法一:dd 写零文件再删除 dd if=/dev/zero of=/zero.fill bs=1M rm -f /zero.fill syncdd会一直写到磁盘满,报 "No space left on device" 是正常的,然后删掉这个文件。注意:如果磁盘是 ext4 且挂载了discard选项,或者用了 SSD,可能不需要这步,但为了保险还是做一下。
更优雅的方式是用zerofree,它只填充空闲块,速度更快,但需要把分区卸载或者以只读挂载:
# 安装 apt-get install zerofree # 进入单用户模式或从 Live CD 启动,卸载分区后执行 zerofree /dev/sda1Windows 下没有直接的dd,但可以用sdelete(Sysinternals 工具):
sdelete -z C:-z参数就是写零清理空闲空间。这个工具微软官方提供,下载后放到虚拟机里执行即可。执行时间取决于磁盘大小和空闲空间,可能比较久,耐心等。
提示:写零操作会让虚拟机磁盘文件暂时膨胀到接近满盘,所以宿主机必须有足够剩余空间。比如虚拟机分配了 60G,实际用了 30G,写零过程中 vmdk 可能涨到接近 60G,压缩后再降下来。宿主机空间紧张的话,先清理宿主机。
4. 用 vmware-vdiskmanager 压缩磁盘
4.1 工具在哪、怎么用
vmware-vdiskmanager是 VMware Workstation 自带的命令行工具,Windows 下在安装目录,通常是:
C:\Program Files (x86)\VMware\VMware Workstation\vmware-vdiskmanager.exeLinux 宿主机上一般在/usr/bin/vmware-vdiskmanager或/usr/lib/vmware/bin/下。
它的核心功能包括:压缩、碎片整理、扩容、转换磁盘类型。我们清理磁盘主要用两个参数:-d(defragment,碎片整理)和-k(shrink,压缩)。
基本语法:
vmware-vdiskmanager -k "路径\虚拟机磁盘.vmdk"4.2 操作顺序:先整理再压缩
正确的顺序是先碎片整理,再压缩。碎片整理把分散的块集中,压缩才能更高效地回收空间。
# 第一步:碎片整理 vmware-vdiskmanager -d "D:\VMs\Ubuntu\Ubuntu.vmdk" # 第二步:压缩 vmware-vdiskmanager -k "D:\VMs\Ubuntu\Ubuntu.vmdk"执行前必须关闭虚拟机,不是挂起,是完全关机。挂起状态下磁盘文件被锁定,工具会报错。
Windows 下如果路径有空格,记得加引号。执行过程会有进度提示,压缩大磁盘可能十几分钟到半小时。
4.3 压缩能回收多少空间
压缩的效果取决于你之前写零是否彻底。我实测过几台:
| 虚拟机 | 压缩前 vmdk | 压缩后 vmdk | 回收比例 |
|---|---|---|---|
| Ubuntu 22.04(开发环境) | 58G | 32G | 45% |
| Windows 10(办公) | 76G | 41G | 46% |
| CentOS 7(服务测试) | 43G | 25G | 42% |
可以看到,只要写零做到位,回收 40% 以上很常见。如果压缩后几乎没变化,八成是写零没做,或者磁盘是厚置备模式。
4.4 厚置备转薄置备
如果你的磁盘是厚置备,-k压缩基本无效,因为厚置备的块是预分配的。这时候需要转换磁盘类型。vmware-vdiskmanager支持-r参数转换:
vmware-vdiskmanager -r "source.vmdk" -t 0 "target.vmdk"其中-t后面的数字代表磁盘类型:
0:单文件薄置备1:拆分薄置备2:预分配单文件3:预分配拆分4:精简预分配拆分(ESXi 用)
转换会生成一个新的 vmdk,原来的保留。转换完成后需要在虚拟机设置里把硬盘指向新文件,确认能正常启动后再删旧的。这个过程比较耗时,而且需要额外空间存放新磁盘,宿主机空间要留够。
注意:转换磁盘类型前务必确认虚拟机内没有快照,有快照的磁盘不能直接转换,必须先删除快照。
5. 图形界面下的清理操作
5.1 磁盘实用工具里的压缩选项
不想敲命令的话,VMware Workstation 的图形界面也提供了压缩功能。选中虚拟机 → 设置 → 硬盘 → 磁盘实用工具 → 压缩。这个按钮背后调用的就是vmware-vdiskmanager -k,效果一样。
但图形界面的压缩不会帮你做碎片整理,也不会帮你写零。所以如果你只是点一下"压缩",效果往往不理想。我的建议还是走命令行,或者至少先在虚拟机里写零,再用图形界面压缩。
5.2 清理磁盘的向导
较新版本的 Workstation 在"虚拟机"菜单下有"管理" → "清理磁盘",会弹出一个向导,引导你选择要清理的磁盘,然后执行压缩。这个向导本质上也是调用同一个工具,适合不熟悉命令行的用户。
不过向导有个限制:它只能处理当前关机状态的虚拟机,而且对拆分磁盘的支持有时候会出问题。我遇到过拆分磁盘压缩到一半报错的情况,最后还是用命令行分片处理才搞定。
5.3 快照管理器的空间回收
前面提过快照,这里再强调一下操作路径。快照管理器里可以删除单个快照,也可以"删除所有快照"。删除所有快照会把所有差异盘合并回基础盘,这个过程会释放大量空间,但耗时可能很长。
合并完成后,建议再做一次碎片整理和压缩,因为合并过程可能产生碎片。我一般的顺序是:删快照 → 开机清理内部垃圾 → 关机写零 → 碎片整理 → 压缩。这一套下来,基本能把虚拟机瘦回刚创建时的水平。
6. 常见问题与排查技巧实录
6.1 压缩时报"磁盘被锁定"怎么办
最常见的原因是虚拟机没完全关机,或者 VMware 的后台进程还在占用文件。解决步骤:
- 确认虚拟机是"关机"状态,不是"挂起"或"休眠"。
- 关闭 VMware Workstation 主界面。
- 打开任务管理器,结束所有
vmware-vmx.exe、vmware.exe进程。 - 如果还不行,重启宿主机,确保没有残留进程。
有时候是杀毒软件在扫描 vmdk 文件导致锁定,临时关闭杀毒软件的实时防护再试。
6.2 压缩后空间没变化
排查顺序:
- 确认磁盘是薄置备,厚置备压缩无效。
- 确认虚拟机内做了写零操作,没写零的话 VMware 无法识别空闲块。
- 确认没有快照,有快照时压缩的是基础盘,差异盘不受影响。
- 确认压缩的是正确的 vmdk 文件,拆分磁盘要指定主文件(不带
-s001后缀的那个)。
6.3 写零时提示空间不足
dd写零会占满整个空闲空间,如果宿主机剩余空间不够,vmdk 涨到一半就失败了。解决办法:
- 先清理宿主机,腾出至少等于虚拟机分配大小的空间。
- 或者分批写零,比如每次写 5G,删掉再写,但这样压缩效果会打折扣。
- 用
zerofree替代dd,它只填充空闲块,不会让 vmdk 膨胀太多。
6.4 虚拟机启动后黑屏或进不去系统
这通常是磁盘操作后引导记录或文件系统出了问题。排查:
- 检查虚拟机设置里硬盘是否还指向正确的 vmdk。
- 用系统安装 ISO 启动,进入救援模式,检查文件系统:
fsck /dev/sda1。 - 如果是引导问题,用
grub-install或bootrec /fixmbr(Windows)修复。
我踩过一次坑:转换磁盘类型后忘了改虚拟机设置,启动时找不到磁盘,黑屏。改回正确路径就好了。
6.5 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 压缩报磁盘锁定 | 虚拟机未关机/进程残留 | 关机、结束 vmware-vmx 进程 |
| 压缩后空间不变 | 厚置备/未写零/有快照 | 转薄置备、写零、删快照 |
| 写零空间不足 | 宿主机剩余空间不够 | 清理宿主机或改用 zerofree |
| 启动黑屏 | 磁盘路径错误/引导损坏 | 检查设置、fsck、修复引导 |
| 压缩中途报错 | 拆分磁盘/磁盘损坏 | 分片处理、检查磁盘完整性 |
| 快照删除很慢 | 差异盘过大 | 耐心等待,勿强制关闭 |
6.6 几个我踩过的坑
第一个坑是在挂起状态下压缩。有次图省事,虚拟机挂起就直接跑vmware-vdiskmanager -k,结果报错不说,还把挂起状态搞坏了,最后只能丢弃挂起状态重新开机。
第二个坑是写零后忘了 sync。dd写完删掉文件,如果没执行sync,数据可能还在缓存里,VMware 压缩时读到的还是旧数据,压缩效果很差。养成写完就sync的习惯。
第三个坑是拆分磁盘只压缩了主文件。拆分磁盘有-s001、-s002等分片,vmware-vdiskmanager处理主文件时会自动处理所有分片,但如果你手动指定了某个分片,就会出错。记住只指定不带分片后缀的主文件名。
第四个坑是宿主机磁盘碎片。虚拟机 vmdk 在宿主机上如果碎片严重,压缩和整理都会很慢。定期对宿主机做磁盘碎片整理(机械硬盘)或者 TRIM(SSD),能明显提升虚拟机磁盘操作速度。
7. 日常维护习惯与自动化思路
清理磁盘不是一劳永逸的事,养成习惯比事后补救更重要。我现在的做法是:每台虚拟机每月做一次内部清理,每季度做一次完整压缩。内部清理包括清日志、清缓存、清临时文件,几分钟搞定;完整压缩放在周末,反正不影响工作。
Linux 虚拟机可以写个简单的清理脚本,用 cron 定期执行:
#!/bin/bash # clean_vm.sh journalctl --vacuum-time=7d apt-get clean rm -rf /tmp/* find /var/log -name "*.gz" -mtime +30 -deleteWindows 虚拟机可以用任务计划程序定期跑磁盘清理和sdelete -z,但sdelete比较耗时,建议手动执行。
另外,创建虚拟机时就规划好磁盘大小和类型,能省很多事。我现在的习惯是:开发环境给 60G 薄置备,办公环境给 80G 薄置备,服务测试给 40G 薄置备。薄置备虽然需要定期清理,但空间利用率高,适合宿主机空间有限的场景。如果宿主机空间充足且追求性能稳定,厚置备也不是不行,只是要接受它不会缩小的现实。
最后分享一个小技巧:如果你有多台虚拟机,可以把它们的清理时间错开,避免同时压缩导致宿主机 IO 爆满。我一般周五晚上压缩一台,周六压缩另一台,周日留给宿主机自己做维护。这样既不影响工作,又能保持磁盘整洁。