How to compact VirtualBox's VDI file size?
Solution 1:
You have to do the following steps:
-
Run defrag in the guest (Windows only)
-
Nullify free space:
With a Linux Guest run this:
dd if=/dev/zero of=/var/tmp/bigemptyfile bs=4096k ; rm /var/tmp/bigemptyfile
Or:
telinit 1 mount -o remount,ro /dev/sda1 zerofree -v /dev/sda1
With a Windows Guest, download SDelete from Sysinternals and run this:
sdelete.exe c: -z
(replace C: with the drive letter of the VDI)
-
Shutdown the guest VM
-
Now run VBoxManage's
modifymedium
command with the--compact
option:With a Linux Host run this:
vboxmanage modifymedium --compact /path/to/thedisk.vdi
With a Windows Host run this:
VBoxManage.exe modifymedium --compact c:\path\to\thedisk.vdi
With a Mac Host run this:
VBoxManage modifymedium --compact /path/to/thedisk.vdi
VBoxManage is located here: /Applications/VirtualBox.app/Contents/MacOS/VBoxManage
This reduces the vdi size.
Solution 2:
I'm on a Windows 7 host with Windows guests, Here is a batch file I wrote to Compact all of the VDIs in a folder tree
echo off
mode con:cols=140 lines=200
cls
:: see https://forums.virtualbox.org/viewtopic.php?p=29272#p29272
:: How can I reduce the size of a dynamic VDI on disk?
:: but that page says to use sdelete -s which is suboptimal.
:: use -z as per http://technet.microsoft.com/en-us/sysinternals/bb897443.aspx
:: First run the sdelete -z c: inside the VMs that zero-out all the free space
:: THEN run this batch file
Title Compacting Free space on Virtual Machine VMs
:: http://ss64.com/nt/for_r.html
:: http://stackoverflow.com/questions/8836368/windows-batch-file-how-to-loop-through-files-in-a-directory/8836401#8836401
Setlocal EnableDelayedExpansion
:: http://ss64.com/nt/delayedexpansion.html ...
:: Notice that within the for loop we use !variable! instead of %variable%.
For /R %CD% %%G IN (*.vdi) DO (
set ohai=%%G
set lastfive=!ohai:~-5!
:: Skip snapshots which are named {guid}.vdi
if NOT !lastfive!==}.vdi (
echo .
echo Compacting %%G
"C:\Program Files\Oracle\VirtualBox\VboxManage.exe" modifyhd "%%G" --compact )
)
pause
exit
I left the links in the comments so you can (sort of) tell how it works.
edit
Well, after all that, I tried the CloneVDI tool and it did a good job in much less time and in one click.
Solution 3:
Debian guest on Windows host using discard/TRIM.
This isn't a direct answer per se, as I'm addressing the problem, not the question. Instead of periodically compacting the image, this solution uses discard to automatically remove unused blocks in the host's VM disk image.
This solution requires a guest filesystem that supports continuous TRIM. The Arch Linux wiki has a list of filesystems supporting TRIM operations.
FDE and cryptoroot are specifically not covered, as there are security concerns and none of the other solutions to this question would allow compacting either. The Arch Linux wiki has information about TRIM and dm-crypt devices.
In theory, this will work for all Linux guests on VBox hosts using VDI storage.
Host configuration
With VBox exited and no VMs running, add discard support to your disks by setting both discard
and nonrotational
for each disk in the config file for the VM. At this time discard
is not in the GUI, but nonrotational
is exposed as the "Solid-state Drive" checkbox. (ref: vbox forums, discard support)
<AttachedDevice discard="true" nonrotational="true" type="HardDisk" [..other options..] >
Boot the VM up, and verify that TRIM support is enabled:
sudo hdparm -I /dev/sda | grep TRIM
Guest Configuration
If LVM is in use, change the discard setting in /etc/lvm/lvm.conf
. (ref: debian wiki, lvm.conf example)
devices {
...
issue_discards = 1
}
In fstab, add the discard
option to the filesystems you wish to auto-discard (ref: debian wiki, fstab example)
UUID=8db6787f-1e82-42d8-b39f-8b7491a0523c / ext4 discard,errors=remount-ro 0 1
UUID=70bfca92-8454-4777-9d87-a7face32b7e7 /build ext4 discard,errors=remount-ro,noatime 0 1
Remount the filesystems to have them pick up their new options.
sudo mount -o remount /
sudo mount -o remount /build
Manually trim free blocks now with fstrim
. fstrim
uses the mounted filesystem, not the block device backing it. Instead of setting continuous discard in fstab
, this could be done on a weekly cron. (The weekly cron is recommended for physical SSDs which may have questionable support for TRIM, but this is not relevant here since underlying SSDs are handled by the host OS. see: ssd trim warning).
fstrim /
fstrim /build
At this point, the size of the filesystems inside the VM and the size of the VM images should be pretty close in value.
Tested with:
- Guest1: Debian 8.7, kernel: linux 4.8 grsec from backports, filesystem: ext4
- Guest2: Debian 9 RC2, kernel: linux 4.9, filesystem: ext4
- Host1: VBox 5.1.14, Win7, image fmt: VDI
- Host2: VBox 5.1.14, Win8.1, image fmt: VDI
Solution 4:
For MacOS Guest do this:
-
Nullify free space in guest system:
diskutil secureErase freespace 0 "/Volumes/Macintosh HD"
(replace /Volumes/Macintosh HD with your drive name)
Shutdown the guest VM
-
Run this command to reduce VDI disk image size
VBoxManage modifyhd /path/to/thedisk.vdi --compact
OR
VBoxManage modifymedium /path/to/thedisk.vdi --compact