压缩 VirtualBox 虚拟卷文件的方法及原理

作为一个 Linux 开发者,部分程序无法或者我们不愿意让它们在自己的系统上运行时,我们会用到虚拟机,比如我使用 VirtualBox,并且安装了许多基于 XP 的虚拟机用来跑各类不可信任的国产软件,但是随着使用时间的增加,会发现一个奇怪的现象,那就是从虚拟机内部 (Guest OS) 看到的大小和实际占用磁盘的大小相差越来越大.


这样对于虚拟机文件的备份、存储和转移而言就非常不利,所以我们需要对 VDI 文件进行 “压缩”.

Method

首先简要提一下网上都能查到的且可用的方法,对于我这种情况 (Host 为 Linux,Guest 为 Windows) 的用户而言其实很简单,就以下几步:

  1. 首先在虚拟机中使用系统自带的磁盘碎片清理工具清理磁盘碎片
  2. technet.microsoft.com/en-us/sysinternals/bb897443.aspx 下载个 SDelete
  3. 在 Guest OS 中 sdelete.exe c: -z 来将 C 盘空余空间清零(我就一个 C 盘)
  4. 虚拟机关机,在外部 Host OS 中执行 vboxmanage modifymedium --compact /path/to/vbox.vdi 对 vdi 文件进行清理

如果你的系统配置和我的不一样的话,看一下文末的第二个参考链接很快就能知道该如何做了.

In-Depth

方法简单易用,但是仅仅可用肯定不行啊,我们得知道为什么要那么做,以及这个方法可用的原因,首先我们看看第 4 个指令 --compact 的含义,重点部分已加粗:

The –compact option can be used to compact disk images, i.e.remove blocks that only contains zeroes. This will shrink a dynamically allocated image again; it will reduce the physical size of the image without affecting the logical size of the virtual disk.
For this operation to be effective, it is required that free space in the guest system first be zeroed out using a suitable software tool.

Attempt with SDlete and BinImage

我们先看一下 SDelete 前后的磁盘碎片分析


似乎从碎片上看不出什么不同,遂决定 --compact 一下后对文件进行分析

由于文件太大我的电脑内存不够,不能直接分析整个文件,所以 将 vdi 文件进行切片,使用指令

1
2
3
4
# compact 前
split --bytes=10M /path/to/VM.vdi /tmp/before/thunder-
# SDelete + compact 后
split --bytes=10M /path/to/VM.vdi /tmp/after/thunder-

此时使用 teaearlgraycold/binimage 对随意一个文件,本文使用 thunder-cl 分卷进行可视化:

1
./binimage-linux-amd64 before/VM-cl before.png --width=1920

观察 thunder-cl 分卷在 SDelete+compact 前后的图片

Before

After

从图片中我们可以简要看出,在 SDelete 并且 compact 之后文件中的洞 (Zerod-Block,也就是纯黑色的部分) 多了一些,不过这依然不能揭示具体的原理,我们换个角度试试~

Disk image files

For more flexible storage management, use a dynamically allocated image. This will initially be very small and not occupy any space for unused virtual disk sectors, but will grow every time a disk sector is written to for the first time, until the drive reaches the maximum capacity chosen when the drive was created. While this format takes less space initially, the fact that VirtualBox needs to expand the image file consumes additional computing resources, so until the disk file size has stabilized, write operations may be slower than with fixed size disks. However, after a time the rate of growth will slow and the average penalty for write operations will be negligible.

通过 VirtualBox 官方的介绍我们得知,对于一个 “dynamically allocated image”,或者说动态的磁盘卷(也是一个稀疏文件),在创建之初占用的空间会非常小,但是每当有磁盘的写入操作的时候,整个卷文件的大小就会增加,换言之,只要在 Guest OS 中有文件 IO 操作,无论是移动文件还是写入新文件,都会导致整个卷文件大小增加,且不可直接逆转,此外,对于动态分配的磁盘卷来说,当达到了它的最大设置容量之后,写入速度会变得比固定大小的卷要慢,估计是整理卷文件前面部分的可以被释放的空间并写入新的数据.

对于稀疏文件的压缩,通常采用的是打洞的办法,由于我不熟悉那个领域,这里就不展开了,有兴趣的读者可以参考第四个参考链接或自行 Google.

Conclusion

通过本文我们可以简要得出一些在使用 VM 上的建议:

  1. 如果磁盘空间足的话,直接使用固定大小的虚拟卷可以带来性能的提升和空间的确定性
  2. 如果使用了动态分配卷且用的是 Windows 作为 Guest OS 的话,记得经常在 Guest OS 中进行磁盘碎片整理
  3. 备份虚拟机文件前要 compact 一下,不过不要想着压缩,VM 文件熵普遍很大,压缩仅仅是浪费时间
  4. 有钱且不担心安全问题的话还是选择 Mac 吧,常用软件支持太多了,又有着很接近 Linux 的玩法

References

  1. Chapter 8. VBoxManage
  2. How to compact VirtualBox’s VDI file size?
  3. virtual box vdi takes up much more room than actual size
  4. 用 fallocate 进行” 文件预留 “或” 文件打洞 “

我的博客使用了Disqus评论框,如果你看不到评论框,那么多半Disqus服务在你所在的地区被墙,请使用代理访问。