VMware Ubuntu 24.04 虚拟机从 124 GB 压缩到 33 GB:快照合并、VMDK 占用与 disk shrink 实战
摘要:记录 Ubuntu 24.04 在 VMware Workstation 中从约 124 GB 收缩到约 33 GB 的过程,解释快照合并、VMDK 分片、Guest 空闲块与 VMware Tools disk shrink 的关系。
@[toc]
在 VMware Workstation 中长期使用 Ubuntu 后,很容易遇到一个看起来矛盾的问题:Ubuntu 内部明明只用了三十多 GB,Windows 上保存虚拟机的目录却已经膨胀到一百多 GB;即使在 Ubuntu 中删除了大量文件,宿主机上的 VMDK 也不会同步缩小。
这次实际环境就是这样:Windows 上的虚拟机目录一度约 124 GB,而 Ubuntu 根文件系统实际只使用约 29~32 GB。处理中还出现了一个很容易误判的阶段:删除快照,并在 VMware 中执行压缩和碎片整理后,虚拟磁盘的“当前大小”反而变成了 88.4 GB。
最终,在确认快照链已经合并、Guest 文件系统只有约 32 GB 有效数据后,通过 VMware Tools 的 disk shrink / 将宿主侧实际占用收缩到约 33 GB。
这次问题的关键不是某一条“清理命令”,而是先分清三个完全不同的容量概念:Guest 文件系统使用量、VMDK 已分配空间、虚拟磁盘逻辑容量。
1. 先看最终现象:197 GB 的文件系统只用了 32 GB
Ubuntu 内部最终确认到的根文件系统状态是:
1 | $ df -h / |
也就是说:
/dev/sda2的逻辑容量约 197 GB;- 当前有效数据约 32 GB;
- 文件系统仍有约 157 GB 可用空间。
与此同时,VMware 配置中的虚拟磁盘最大容量是 200 GB,而 Windows 上整个虚拟机目录此前约 124 GB。
这几个数字并不冲突,因为它们统计的不是同一层:
| 数值 | 所在层 | 含义 | 本次案例 |
|---|---|---|---|
df -h / 已用空间 |
Ubuntu/ext4 | 当前仍属于有效文件的数据块 | 约 29~32 GB |
| VMware“当前大小” | VMDK | 宿主机已经为虚拟磁盘实际分配的空间 | 中间阶段 88.4 GB |
| VMware“最大大小” | 虚拟磁盘逻辑容量 | Guest 最多能看到/使用的磁盘容量 | 200 GB |
| Windows 虚拟机目录 | NTFS/宿主机 | VMDK、快照、内存状态、日志等文件总和 | 最初约 124 GB |
因此,“最大大小 200 GB”并不意味着 Windows 必须立即占 200 GB。真正的问题是:历史上已经写入过、后来又在 Ubuntu 中释放的块,是否已经被转换成宿主机可以真正回收的空间。
2. 第一处关键线索:当前磁盘并不在基础 VMDK 上
最初查看 VMware 的硬盘设置时,磁盘文件指向的是:
1 | E:\ubuntu24.04\Ubuntu24.04-000002.vmdk |
而不是基础磁盘:
1 | E:\ubuntu24.04\Ubuntu24.04.vmdk |
同时目录中存在两组明显不同的 VMDK 分片:
1 | Ubuntu24.04-s001.vmdk |
以及:
1 | Ubuntu24.04-000002-s001.vmdk |
这里最容易误判的是 -s001 这种名字。对于“硬盘内容存储在多个文件”的 VMware 虚拟磁盘,Ubuntu24.04-s001.vmdk、-s002.vmdk 等本身就是基础 VMDK 的分片,并不等价于快照。
真正表明当前位于快照增量层的是前面的 -000002。
下面这张图把当时的磁盘关系拆开来看:
基础 VMDK 提供父磁盘数据;Ubuntu24.04-000002.vmdk 及其 -sxxx 分片记录快照之后的增量变化。当前 Guest 看到的文件系统视图,是基础层与当前增量层组合后的结果。
这也解释了为什么当时 VMware 界面显示的“当前大小 26.6 GB”不能直接拿去和 Windows 整个虚拟机目录比较:26.6 GB 只是当前增量层相关的已分配空间,父磁盘仍然必须保留。
3. 删除快照后,为什么“当前大小”反而变成 88.4 GB
在确认旧快照不再需要后,通过 VMware 的快照管理功能删除快照,并等待其完成合并。
完成后,硬盘设置重新指向:
1 | E:\ubuntu24.04\Ubuntu24.04.vmdk |
原来的:
1 | Ubuntu24.04-000002.vmdk |
不再作为当前增量层存在。
但此时 VMware 显示:
1 | 当前大小:88.4 GB |
表面上看,26.6 GB → 88.4 GB 像是“删除快照把磁盘弄大了”,实际上这是快照合并后的正常现象。
删除快照并不是简单把 delta 文件扔掉。为了保留当前系统状态,快照期间产生的有效数据必须被合并回父磁盘。于是原来分散在“基础层 + 增量层”中的有效块重新收敛到基础 VMDK 中,VMware 此时统计到的基础盘已分配空间自然会变大。
目录中大量 Ubuntu24.04-sxxx.vmdk 在快照删除期间连续更新,也与这一合并过程一致。
所以,88.4 GB 并不代表快照删除失败,而是说明快照链问题已经解决,接下来要处理的是 VMDK 内仍然占用宿主空间的历史数据块。
4. 为什么碎片整理和“压缩”之后仍然远大于 32 GB
在快照删除完成后,已经尝试过 VMware 界面中的碎片整理和压缩,但“当前大小”仍然约 88.4 GB。
原因在于 Linux 文件删除与宿主机空间回收之间还隔着一层。
在 ext4 中删除文件后,文件系统主要做的是把对应块重新标记为空闲。对 Ubuntu 来说,这些块已经可以重新利用;但块里面过去的数据内容并不会因为“文件被删除”就自动变成 VMware 一定可以丢弃的宿主机空洞。
可以把这一关系理解为:
1 | Ubuntu 删除文件 |
所以本案例中真正要解决的是:让 VMware 明确知道哪些 Guest 空闲区域已经没有有效数据,可以安全地从 VMDK 的实际分配空间中回收。
5. fstrim -av 没有输出,但这不是最终阻塞点
Ubuntu 中先尝试执行:
1 | sudo fstrim -av |
实际结果没有输出。
这里不应该凭空把它解释为“文件系统异常”或者“TRIM 一定失败”。从现有证据只能确认:这次命令没有得到可报告的 TRIM/DISCARD 输出。
更重要的是,本次环境中的 VMware Tools 本身提供了磁盘 shrink 能力,因此最终空间回收并不依赖 fstrim 成功返回某个 trimmed 数值。
确认 VMware Tools 版本:
1 | $ vmware-toolbox-cmd -v |
查看磁盘相关子命令:
1 | $ vmware-toolbox-cmd help disk |
这里最关键的一行是:
1 | shrink <location>: wipes and shrinks a file system at the given location |
它明确说明 shrink 不只是宿主机侧再执行一次“压缩”,而是会先处理文件系统空闲区域,再完成虚拟磁盘收缩。
首次直接执行:
1 | vmware-toolbox-cmd disk list |
得到:
1 | vmware-toolbox-cmd: You must be root to perform disk operations. |
这不是工具损坏,而是权限要求。磁盘操作需要 root,因此后续使用:
1 | sudo vmware-toolbox-cmd disk list |
以及:
1 | sudo vmware-toolbox-cmd disk shrink / |
6. 实际空间回收路径:124 GB → 88.4 GB → 33 GB
把整个过程放在一起看,关键步骤不是“反复点压缩”,而是先处理快照链,再把 Guest 空闲区域真正转化为 VMware 可以回收的 VMDK 空间。
本次实际顺序可以归纳为以下几步。
6.1 先确认 Guest 里确实存在大量空闲空间
1 | df -h / |
结果:
1 | /dev/sda2 197G 32G 157G 17% / |
如果 Guest 本身已经使用 150 GB,就不应该期待 VMDK 最终收缩到三十多 GB。这个检查决定了后续空间回收是否有意义。
6.2 处理快照链,不手工删除任何 VMDK
当前磁盘如果仍指向:
1 | Ubuntu24.04-00000x.vmdk |
应优先通过 VMware 的快照管理器删除不再需要的快照,让 VMware 自己完成增量数据合并。
不要直接从资源管理器删除:
1 | Ubuntu24.04-000002.vmdk |
也不要因为基础盘分片很多,就误删:
1 | Ubuntu24.04-s001.vmdk |
这两类文件承担的角色不同,但都不应该靠文件名猜测后手工清理。
6.3 快照合并后重新确认基础盘状态
本次合并完成后:
1 | 磁盘文件:Ubuntu24.04.vmdk |
这里的 88.4 GB 是下一步需要回收的 VMDK 已分配空间,而不是 Guest 当前有效文件量。
6.4 用 VMware Tools 从 Guest 侧执行 shrink
确认工具支持 disk shrink 后执行:
1 | sudo vmware-toolbox-cmd disk shrink / |
执行期间不要强制关闭 VMware、暂停虚拟机或 Ctrl+C 中断。这个操作会处理大量文件系统空闲块,中间过程可能明显慢于普通命令。
本次实际执行最终成功,宿主侧虚拟机占用收缩到约:
1 | 33 GB |
与 Ubuntu 内部约 32 GB 的实际使用量已经处于同一数量级。
7. 为什么最终不是“精确 32 GB”
虚拟机最终约 33 GB,而 df -h / 显示已使用约 32 GB,这已经是非常合理的结果。
不应该把目标理解为:
1 | Guest 已用 32 GB |
两者之间还可能存在:
- ext4 文件系统元数据;
- swap 文件或其他 Guest 数据;
- VMDK descriptor 与 extent 元数据;
- VMware 的分配粒度;
- 虚拟机目录中的配置、日志等其他文件。
判断是否成功,更合理的标准是:VMDK 是否已经从明显偏离 Guest 有效数据量的历史膨胀状态,回落到与当前有效数据量接近的数量级。
本次从约 124 GB 回落到约 33 GB,已经满足这一目标。
8. 为什么没必要把 200 GB 逻辑磁盘继续改成 50 GB
空间回收完成后,VMware 中仍然显示:
1 | 最大大小:200 GB |
这是正常且合理的。
此时的状态可以同时成立:
1 | Guest 最多可使用:200 GB |
动态增长磁盘的价值就在这里:逻辑容量可以预留得较大,而宿主机只为真正写入并仍需保留的数据承担实际空间。
如果继续要求把逻辑容量从 200 GB 改成 50 GB,问题就不再是“回收 VMDK 空闲块”,而会涉及:
- ext4 文件系统缩容;
- 分区边界缩容;
- 虚拟磁盘容器缩容或迁移到更小的新盘;
- 分区表、启动链和数据完整性检查。
这条路线的风险和复杂度明显更高,而对当前问题没有实际收益。因此本案例在宿主占用已经回落到约 33 GB 后,就没有继续缩小 200 GB 逻辑上限的必要。
9. 这次排查真正需要记住的三层关系
这次问题表面上是“为什么虚拟机这么大”,真正容易混淆的是不同层的容量数字。
可以把它们分成三层:
| 层级 | 关注的问题 | 本次对应现象 |
|---|---|---|
| Ubuntu/ext4 | 哪些逻辑块仍属于有效文件 | df -h / 约 32 GB 已用 |
| VMware/VMDK | 哪些虚拟磁盘块已经在宿主机实际分配 | 快照合并后约 88.4 GB |
| Windows/NTFS | 整个虚拟机目录实际占多少宿主机空间 | 最初约 124 GB,最终约 33 GB |
文件在 Ubuntu 中被删除,只完成了第一层状态变化;删除快照解决的是 VMDK 版本链与父子依赖;vmware-toolbox-cmd disk shrink / 才把 Guest 的空闲区域进一步转换成宿主机能够实际回收的 VMDK 空间。
以后再遇到“Ubuntu 明明没用多少空间,VMware 为什么占这么大”的问题,先按这个顺序判断:
- 当前看到的数字到底是 Guest 已用空间、VMDK 当前大小,还是虚拟磁盘最大容量;
- 当前磁盘是否仍然指向
-00000x.vmdk快照增量层; - 快照合并完成后,Guest 空闲区域是否真正经过 VMware 能识别的 shrink/回收路径。
只要把这三层拆开,124 GB → 88.4 GB → 33 GB 这组看似反常的数字就能完整解释清楚。









