156

I'm using Ubuntu 20.04 on WSL2 on Windows 10, and I noticed that after removing files on Ubuntu I was not getting the space back that was taken up by the removed files. For example: Before I deleted files on Ubuntu it showed on Windows explorer that my free space on the (C:) drive was around 46GB. Then after I deleted around 10GB of files, which in my case where some temporary Gatsby sites, it resulted in even less free space, around 45GB, which I thought was very weird.

So how can I get back those unused bits? Is there some terminal command which I can use or can I do something via the Windows GUI or something?

Franck Dernoncourt
  • 24,246
  • 64
  • 231
  • 400

9 Answers9

163

There are a few options here, but I'm moving things around in this edit. My "original" answer is back to being the preferred method. See the bottom of this answer for an alternative, experimental method.

"Original" Answer (Preferred)

There's a WSL Github issue open on this topic. WSL will automatically grow the virtual disk (ext4.vhdx), but shrinking it to reclaim unused space is something that must currently be done manually.

The first thing you'll need to do is know the location of your ext4.vhdx. For a default Ubuntu installation, it should be in something like %USERPROFILE%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\

Then there are several techniques that you can use to remove the unused space. I recommend you start with a wsl --shutdown and copy the vhdx as a backup to start. If you are running Docker Desktop, also shut it down, otherwise it may inadvertently attempt to restart WSL after your --shutdown.

  • If you are on Windows Professional or higher, you can install Hyper-V and use the Optimize-VHD commandlet as described in the original issue. .

  • On Windows Home (and higher) you can use diskpart as described in this comment.

  • Exporting the WSL distro and re-importing it into a new WSL instance (as in this comment) will also reclaim the space. Note that you will need to reset the default username after an import. See here (and here for alternative options).

I have tested and confirmed both the second and third techniques personally.


Alternative (Warning)

The following feature remains in "Experimental" status a year after its appearance, and while I'm sure it works well for many, too many users continue to report corruption of their WSL Distributions and sometimes even the Windows host filesystem when using it.

Thanks to comments from @MarkCh and @willnode, I've edited the answer to both move this method under the original answer as well as highlight this warning.

In September, 2023, a pre-release of WSL (2.0.0) enabled a new "sparse" mode for disk images which is intended to automatically shrink the image when files are removed. (Especially given the warning above) Always maintain good backups, especially when using newer features that affect the entire virtual drive. I have not tested this personally yet.

While that said, from the DevBlog announcement, you can convert an existing disk image to sparse with the following command from PowerShell:

wsl --manage <distro> --set-sparse true

You can also add the following to your .wslconfig (located in your Windows profile directory, not inside WSL) to have any newly created distro image be sparse:

[experimental]
sparseVhd=true
NotTheDr01ds
  • 28,025
68

When the command let optimize-vhd is not available in your system do the following:

Shutdown the wsl before managing its disk

wsl --shutdown

Save the following script as compact-disk.txt

select vdisk file="C:\Users\%username%\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\LocalState\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk

Open prompt as Administrator and run the saved script above

diskpart /s <SAVED_SCRIPT_FOLDER_PATH>\compact-disk.txt
49
  • Activate Hyper-V module in windows features (control-panel -> Turn windows features on or off -> activate Hyper-v -> restart). This is required to activate optimize-vhd command.
  • Open windows powershell as admin: First, press Windows+R to open Run, and then type “powershell” in the text box. Next, press Ctrl+Shift+Enter. Windows PowerShell will open in admin mode. In powershell, run following commands.
  • wsl.exe --shutdown
  • cd into ext4.vhdx folder that typically is cd C:\Users\<user>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\LocalState\
  • optimize-vhd -Path .\ext4.vhdx -Mode full (Make sure the ext4.vhdx is not clicked on by mouse, because that would lead to the error of the the file is being used by another process in powershell)
Masih
  • 591
8

I found a solution to optimize WSL disk size without using the experimental option.

Here are the steps on how to reduce WSL disk size:

  1. Shutdown WSL:

Open a PowerShell or command prompt window with administrator privileges. Run the command: wsl --shutdown

  1. Identify the virtual disk file:

The virtual disk file is typically located at: C:\Users\<your_username>\AppData\Local\Packages\<distro_package_name>\LocalState\ext4.vhdx Replace <your_username> and <distro_package_name> with the appropriate values.

  1. Choose a method based on your Windows version:

For Windows Pro or higher:

  • Use Optimize-VHD:
  • Open PowerShell as administrator.
  • Navigate to the directory containing the ext4.vhdx file.
  • Run the command: Optimize-VHD -Path .\ext4.vhdx -Mode full

For Windows Home:

  • Use diskpart:
  • Open a command prompt as administrator.
  • Run the command: diskpart
  • Inside diskpart, run the following commands:
  • select vdisk file="<path_to_ext4.vhdx>"
  • compact vdisk
6

If you are running docker desktop, you might be able to reclaim more data using "Docker Desktop -> Troubleshooting -> Purge Data": enter image description here

For me, running "optimize-vhd" alone did not change much, but using docker's purge reduced my image from 40GB to 1.5GB.

Found this solution here

Nir
  • 161
3

With this self-elevate script you can compact multiple vhdx at once.

# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
    if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
        $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
        Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
        Exit
    }
}

#Full Path of vhdx file $d1 = #Ex: "E:\Docker\wsl\data\ext4.vhdx" $d2 = "" $d3 = "" $d4 = "" $d5 = "" $d6 = ""

$paths = $d1, $d2, $d3, $d4, $d5, $d6

foreach ($file in $paths) { echo "" echo "Befor Shrinking File sizes in MB" Get-ChildItem -Path $file | Select-Object FullName, @{Name = "Size"; E = { $_.Length / 1MB } } echo "" echo "---------" echo "Shrinking $file" echo "---------"

wsl --shutdown
Optimize-VHD -Path $file -Mode Full

echo &quot;&quot;
echo &quot;After Shrinking File sizes in MB&quot;
Get-ChildItem -Path $file | Select-Object FullName, @{Name = &quot;Size&quot;; E = { $_.Length / 1MB } }
echo &quot;&quot;
echo &quot;&quot;
echo &quot;&quot;
echo &quot;&quot;

}

Read-Host -Prompt "Press Enter to exit"

btw, with a little tweak you can also run it on startup ("Start Docker when you login" should be disabled).

Franck Dernoncourt
  • 24,246
  • 64
  • 231
  • 400
1

I'm using a recent version of WSL 2 and it seems to respond to fstrim for me, which is much faster than compacting the disk.

I'm getting some space gains by running this inside Ubuntu:

sudo fstrim -v -a
zap
  • 11
0

If you have Docker installed and a partitioned SDD, i had similar space issues and here instead of purging the docker image`s via the troubleshoot pane, i just changed the location in Docker Desktop > settings "Disk image location" and pointed that to my D: drive which at least has some space, in turn it also freed up allot of space on my system drive "C:" clearing locally stored docker images i had created. Hopefully someone finds this useful.

-1

I moved my ext4.vhdx from C: to another drive (like D:) and the size shrank from 32 GB to 3.1 GB.

My step is:

  1. backup the original ext4.vhdx to somewhere else

  2. shut down wsl

    wsl --shutdown

  3. check your ubuntu name

    wsl -l -v

my case is:

  NAME              STATE           VERSION
* Ubuntu-22.04      Stopped         2
  docker-desktop    Stopped         2
  1. export ubuntu (create the folder if not exists)

    wsl --export Ubuntu-22.04 "D:\wsl-backup\ubuntu22.tar"

  2. unregister

    wsl --unregister Ubuntu-22.04

  3. import to D: (create the folder if not exists)

    wsl --import Ubuntu-22.04 "D:\WSL\Ubuntu22" "D:\wsl-backup\ubuntu22.tar" --version 2