WSL、VirtualBox内でファイルを削除しても容量が増えない件

WSL内で、Dockerのキャッシュやイメージなど比較的サイズの大きいファイルを削除しても、ホストであるWindowsから見ると一向に容量が削減できていません。特にDcoker版のstable diffusionのモデルを削除してもまったく効果がないのです。そこで、WSL(Windows Subsystem for Linux)内でファイルを削除してもホストのディスク容量が減らない問題について説明します。

WSLでは、LinuxファイルシステムはWindowsのファイルシステム上に仮想的に存在します。WSL 1とWSL 2ではこの挙動に少し違いがありますが、基本的にはWSL内でファイルを削除しても、Windows側で即座にディスク容量が開放されない場合があります。これは、WSLが使用する仮想ディスクの管理方法によるものです。

WSL 2の場合

WSL 2では、実際のLinuxカーネルを使用し、ファイルシステムはVHD(Virtual Hard Disk)ファイル内に格納されます。ファイルを削除しても、VHDのサイズは自動的には縮小されません。VHDファイルサイズを減らすには、手動でディスクの圧縮を行う必要があります。これを行うには、一時的にWSLインスタンスを停止し、Optimize-VHD コマンドをPowerShellで実行する方法があります。VMwareでもゲストOSでアプリなどをアンインストールしても削減されないので、圧縮していました。この場合GUIなツールがあるので比較的簡単でした。

WSL 1の場合

WSL 1では、ファイルシステムはWindowsのファイルシステム内に直接統合されています。しかし、ここでもファイル削除後の即時のディスク容量の開放は見られないことがあります。これは、Windowsのファイルシステムが削除されたファイルの領域をすぐには再利用しないためです。

解決策

  • ディスクの圧縮: WSL 2でVHDファイルのサイズを減らしたい場合、ディスクの圧縮を試みることができます。
  • 一時ファイルの削除: WSL内でsudo apt-get cleanrmコマンドを使用して不要なファイルやキャッシュを削除することで、いくらかのディスクスペースを開放することができます。
  • WSLの再起動: 特にWSL 1では、WSLを再起動することでWindowsがファイルシステムの整理を行い、ディスク容量が回復することがあります。

しかし、Optimize-VHDコマンドでエラーになることがあります。

PS C:WindowsSystem32> Optimize-VHD Optimize-VHD: The term 'Optimize-VHD’ is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Optimize-VHD コマンドが認識されないというエラーメッセージが表示された場合、Hyper-V PowerShell モジュールがインストールされていない、または適切にロードされていない可能性があります。Optimize-VHD は、Hyper-V の機能を管理するための PowerShell コマンドレットの一部であり、Hyper-V 機能が有効になっている Windows システムで利用可能です。

解決策

  1. Hyper-V 機能の確認と有効化: Optimize-VHD を使用するには、Hyper-V が Windows 上で有効になっている必要があります。ただし、Hyper-V は Windows 10 Pro, Education, または Enterprise エディションのみで利用可能です。Windows 10 Home エディションでは使用できません。Hyper-V を有効にするには:
    • コントロールパネルを開きます。
    • プログラムと機能に移動し、Windows の機能の有効化または無効化を選択します。
    • リストからHyper-Vを見つけ、チェックを入れます。
    • OKをクリックし、指示に従ってコンピューターを再起動します。
  2. Hyper-V PowerShell モジュールのインストール: Hyper-V 機能が有効であるにもかかわらず、Optimize-VHD コマンドが利用できない場合は、Hyper-V PowerShell モジュールがインストールされていない可能性があります。次のコマンドを使用して、Hyper-V PowerShell モジュールをインストールできます。

    Install-WindowsFeature -Name Hyper-V-PowerShell

    上記のコマンドを実行するには、PowerShell を管理者権限で開く必要があります。
  3. PowerShell の再起動: モジュールをインストールした後、PowerShell セッションを再起動すると、新しくインストールしたコマンドレットが認識されるようになります。

ここからは、HOMEエディションでも削減する方法を紹介します。

diskpartcompact vdiskコマンド」を使用して動的に拡張する仮想ハードディスク(VHD)ファイルの物理サイズを減らすことが可能です。この方法は、VHDの未使用スペースを圧縮し、実際に占めるディスクスペースを削減するために用いられます。このコマンドは特に、WSL 2で使用されるVHDファイルのサイズ管理に有効です。

使用方法

  1. 管理者としてPowerShellまたはコマンドプロンプトを開きます。
  2. diskpartを実行して、DiskPartツールを起動します。
  3. DiskPartプロンプトで、select vdisk file="ファイルのパス"コマンドを使用して、対象のVHDファイルを選択します。ここでの「ファイルのパス」は、縮小したいVHDファイルのフルパスです。
  4. compact vdiskコマンドを実行して、VHDファイルのサイズを縮小します。

注意点

  • バックアップの重要性: いかなるディスク操作を行う前には、失われる可能性のあるデータに対してバックアップを取ることが重要です。
  • WSLのシャットダウン: WSLインスタンスをcompact vdiskコマンドを実行する前にシャットダウンする必要があります。これはwsl --shutdownコマンドを使用して行います。ゲストOSをシャットダウンすることは重要です。ディスクの縮小操作は、ゲストOSが実行中では行えません。
  • 対象のVHDファイル: WSL 2が使用するVHDファイルの場所は、通常、Windowsのユーザープロファイルディレクトリ内の$HOMEAppDataLocalPackagesに関連するフォルダ内にあります。正確なパスは、インストールされているLinuxディストリビューションによって異なります。

コマンドプロンプト(cmd.exe)では、環境変数の参照方法がPowerShellと異なります。PowerShellでは$HOME${HOME}といった表記でユーザーホームディレクトリへのパスを参照できますが、コマンドプロンプトでは%USERPROFILE%を使用して同様の操作を行います。現在のユーザーのプロファイルディレクトリ内のAppDataLocalPackagesディレクトリに移動します。%USERPROFILE%は、現在ログインしているユーザーのホームディレクトリ(通常はC:Users<ユーザー名>)へのパスを表します。

・シャットダウンについて。
ゲストOS内から直接シャットダウンすることは可能であり、場合によっては推奨される方法です。WSL(Windows Subsystem for Linux)を使用している場合、Linuxディストリビューション(例えばUbuntu)のウィンドウを単に閉じるだけでは、バックグラウンドプロセスが引き続き実行されることがあります。これは、WSLセッションがバックグラウンドでアクティブな状態を維持するため、リソースを消費し続ける可能性があるためです。

WSLでのシャットダウン方法

  1. ゲストOS内でシャットダウンコマンドを使用: UbuntuなどのLinuxディストリビューションでshutdownコマンドを使用することができます。シャットダウンをすぐに実行するには、ターミナルで以下のコマンドを入力します。
sudo shutdown now

このコマンドは、現在のセッションを安全に終了し、Linuxシステムをシャットダウンします。こちらは私が通常使用している方法です。WindowsのコマンドプロンプトまたはPowerShellからWSLインスタンス全体をシャットダウンすることもできます。これは、すべてのLinuxセッションを終了し、WSLサービスを停止する方法です。先に述べた、wsl --shutdownです。

コマンドプロンプトでのファイルの場所
%USERPROFILE%AppDataLocalPackages
PowerShellでのファイルの場所
$HOMEAppDataLocalPackages

WSL(Windows Subsystem for Linux)を使用している場合、インストールされているLinuxディストリビューション(例えばUbuntu)のデータは、Windowsの現在のユーザープロファイルディレクトリ内の特定の場所に保存されます。具体的には、AppDataLocalPackagesディレクトリ内にあります。

Ubuntuの場合、そのデータはCanonicalGroupLimited.UbuntuonWindows...のような名前のフォルダ内に保存されています。フォルダ名はインストールされているUbuntuのバージョンやWSLのバージョンによって異なることがあります。このフォルダ内には、Linux環境のファイルシステムが含まれており、LocalStateサブフォルダ内の仮想ハードディスクファイル(拡張子が.vhdxのファイル)にアクセスすることで、WSLのLinuxディストリビューションのデータに直接アクセスすることができます。

例えば、WSLでUbuntuを使用している場合、仮想ディスクのパスは以下のようになる可能性があります。

C:UsersYourUsernameAppDataLocalPackagesCanonicalGroupLimited.UbuntuonWindows...LocalState

ここで、YourUsernameは自分のWindowsユーザー名に置き換えてください。また、CanonicalGroupLimited.UbuntuonWindows...の部分は、実際にインストールされているUbuntuのバージョンによって異なる名称になります。

マイクロソフトの公式ドキュメントを参考にすることは、常に最新かつ正確な情報を得るための最良の方法です。

実際に試してみる。
diskpartコマンドをpowershellかコマンドプロンプトを起動して入力します。この時、管理者権限で開かなくても、diskpartコマンドを入力するとユーザーアカウントの制御ウインドウが表示され、diskpartを使用できました。ウィンドウが2つ起動することになります。powershellを管理者権限で起動して、入力すると1つの画面で使用できるようです。以下のように表示されます。

Microsoft DiskPart バージョン 10.0.22621.1

Copyright (C) Microsoft Corporation.
コンピューター: N4060

DISKPART>

diskpartはディスクパーティションの作成、削除、フォーマットなど、ディスクに関連する管理作業を行うWindowsのコマンドラインユーティリティです。ファイルやフォルダの移動、コピー、削除などのファイルシステムレベルの操作は、diskpartの機能範囲外です。ということで次のように入力します。使用しているVHDファイルをdiskpart内で選択します。これを行うには、VHDファイルのフルパスを指定してselect vdiskコマンドを使用します。ここで、"C:pathtoyourvhdx.file"は、圧縮したいVHDファイルの実際のパスに置き換えます。

select vdisk file="C:pathtoyourvhdx.file"

VHDファイルが選択された後、以下のコマンドを入力して圧縮を実行します。

compact vdisk

以下は実際に表示されたメッセージです。ext4.vhdxはWSLを複製したので、この場所にあります。

https://minokamo.tokyo/2024/01/23/6798/

DISKPART> select vdisk file="c:wslubuntu1ext4.vhdx"

DiskPart により、仮想ディスク ファイルが選択されました。

DISKPART> compact vdisk

100% 完了しました

DiskPart により、仮想ディスク ファイルは正常に圧縮されました。

DISKPART>

VirtualBoxで使用される.vdiファイル(VirtualBox Disk Image)も、ディスクスペースを節約するためにサイズを縮小することが可能です。VirtualBoxでは、動的に拡張されるディスクイメージが使用される場合、ゲストOS内でデータを削除しても、ホストOSから見たディスクイメージのサイズは自動的には縮小しません。しかし、VirtualBoxにはディスクイメージのサイズを手動で縮小するツールが含まれています。

VirtualBoxのディスクイメージのサイズを縮小する手順:

  1. ゲストOSのシャットダウン: ゲストOSをシャットダウンします。ディスクの縮小操作は、ゲストOSが実行中では行えません。
  2. 空きスペースのゼロ埋め: ゲストOS内で使用されていないディスクスペースをゼロで埋める必要があります。Linuxゲストの場合は、sudo dd if=/dev/zero of=/zero.fill; sync; sudo rm -f /zero.fillのようなコマンドを使って実行します。Windowsゲストの場合は、SDelete(Sysinternalsから提供されているツール)を使用して未使用スペースをゼロ埋めできます。
  3. VirtualBoxのディスク管理ツールを使用: ゲストOSのシャットダウン後、ホストOSでコマンドラインまたはターミナルを開きます。VirtualBoxのVBoxManageコマンドを使用してディスクイメージを縮小します。コマンドは次のようになります(ファイルパスとファイル名は適宜置き換えてください)。
    VBoxManage modifymedium --compact C:pathtoyourvirtualdisk.vdi

このコマンドは、.vdiファイル内のゼロで埋められたスペースを圧縮し、物理ファイルのサイズを縮小します。

mamu@ubuntu22s:~$ sudo dd if=/dev/zero of=/zero.fill; sync; sudo rm -f /zero.fill
[sudo] password for mamu:
dd: writing to '/zero.fill’: No space left on device
24468585+0 records in
24468584+0 records out
12527915008 bytes (13 GB, 12 GiB) copied, 36.0836 s, 347 MB/s

実行したコマンドとその結果は期待通りのものです。このコマンドは、ゲストOS内の未使用スペースをゼロで埋めるために使用されます。このプロセスは、VirtualBoxやVMwareなどの仮想化ソフトウェア、またはWSL 2などで使用される仮想ディスクの物理サイズを縮小する前の準備作業として有効です。

コマンドの各部分の説明は以下の通りです。

  • sudo dd if=/dev/zero of=/zero.fill/dev/zeroから読み取ったデータ(実質的にはゼロの連続)を/zero.fillファイルに書き込みます。これにより、ゲストOSのディスク上の未使用領域がゼロで埋められます。
  • sync:ファイルシステムのバッファを強制的にディスクにフラッシュし、すべての書き込みが物理ディスクに完了するのを保証します。
  • sudo rm -f /zero.fill:使用済みのゼロ埋めファイルを削除し、そのスペースを再び利用可能にします。

dd: writing to '/zero.fill': No space left on deviceというメッセージは、ディスクの空きスペースがすべてゼロで埋められ、それ以上書き込むスペースがなくなったことを意味します。これは正常な挙動で、このプロセスの目的を達成した証拠です。コマンドによって、約13GBのデータがディスクに書き込まれ、その後ファイルが削除されました。これをやるうとやらないでは、雲泥の差が出ます。

この手順の後、仮想ディスクのサイズを縮小する操作(例えば、VirtualBoxの場合はVBoxManage modifymedium --compactコマンド)を行うと、ゼロで埋められた領域を効率的に圧縮でき、結果として仮想ディスクの物理サイズが減少します。この操作は、特にディスクイメージのバックアップや移動を行う前に有効です。

VBoxManage.exeは通常以下のフォルダにあります。

C:Program FilesOracleVirtualBox

このフォルダに移動して(コマンドプロンプトで)コマンドを実行します。仮想ハードディスクがあるフォルダ名にスペースが含まれているとエラーになりました。そのようなときは、一度.vdiファイルを別のフォルダに移動しておきます。また、.vboxには仮想ハードディスクの場所の記述があるらしく、このファイルもいっしょに移動しておかないとエラーになります。圧縮後、元の場所に2ファイルを移動します。エラーは以下のように表示されるようです。

VBoxManage.exe: error: Cannot register the hard disk 'C:temp1ubuntu22.vdi’ {2bb52558-b25e-49f7-aea3-7280019095e7} because a hard disk 'C:UsersminokVirtualBox VMsubuntu22ubuntu22.vdi’ with UUID {2bb52558-b25e-49f7-aea3-7280019095e7} already exists
VBoxManage.exe: error: Details: code E_INVALIDARG (0x80070057), component VirtualBoxWrap, interface IVirtualBox, callee IUnknown
VBoxManage.exe: error: Context: “OpenMedium(Bstr(pszFilenameOrUuid).raw(), enmDevType, enmAccessMode, fForceNewUuidOnOpen, pMedium.asOutParam())" at line 201 of file VBoxManageDisk.cpp

ゲストOSでファイルを削除してもホストOSから見て容量が全く増えない理由は、主に仮想マシンやコンテナー技術(例:WSL、VMware、VirtualBoxなど)が使用するディスクイメージファイルの管理方法に関連しています。特にWSL 2や仮想マシンの場合、いくつかの主要な要因がこれに寄与します。

1. 動的に拡張されるディスクイメージ:

多くの仮想マシンやWSL 2では、ディスクイメージが動的に拡張されるタイプで作成されます。これは、イメージファイルが実際に使用する容量だけをディスク上に占め、ゲストOS内でデータが追加されるにつれてファイルサイズが増加することを意味します。しかし、ゲストOS内でファイルを削除しても、ディスクイメージファイル自体のサイズは自動的には減少しません。つまり、ファイルを削除しても実際のディスク使用量が減少するわけではないのです。

2. ファイルシステムの違い:

ゲストOS(特にLinuxを実行しているWSL 2など)とホストOS(Windows)では、ファイルシステムが異なります。ゲストOS内でファイルを削除しても、その変更がホストOSのファイルシステムレベルで即座に反映されるわけではありません。特に、WSL 2の場合、LinuxファイルシステムはVHD(仮想ハードディスク)内に格納されており、このVHDのサイズ管理はWindowsのファイルシステムとは独立しています。

3. ディスクの圧縮や最適化が必要:

動的VHDや仮想ディスクイメージの物理的なファイルサイズを減らすためには、特定の圧縮または最適化プロセスを手動で実行する必要があります。例えば、Optimize-VHDコマンド(Hyper-Vが有効なWindows Pro以上で使用可能)や、diskpartcompact vdiskコマンドを使用して、未使用のディスクスペースを圧縮することができます。

4. データの断片化:

ファイルシステム内でファイルが削除されると、そのファイルが占めていたスペースは「未使用」とマークされますが、物理ディスク上の空きスペースが即座に再編成されるわけではありません。特に、大量の小さなファイルが削除された場合、ディスクの断片化により実際に利用可能な空きスペースが少なく見えることがあります。

300GBの仮想ハードディスクが5GBになった理由。

ゼロ埋めと仮想ディスクの圧縮操作によって、仮想ハードディスクの物理サイズを大幅に縮小することが可能です。特に、ディスク内の多くのデータが削除された後や、大量の未使用スペースが存在する場合にこの効果は顕著に現れます。

仮想化環境では、動的に拡張するディスクイメージファイルが使用されることが多く、この種のファイルは実際に使用されているデータの量に基づいて物理サイズが変化します。しかし、ゲストOS内でファイルを削除しても、対応するディスクイメージファイルのサイズが自動的には減少しないため、ゼロ埋めと圧縮のプロセスが必要になります。

  • ゼロ埋めは、未使用スペースをゼロで埋めることで、圧縮プロセスがこれらの領域を効率的に識別し、圧縮することを可能にします。
  • 圧縮プロセスでは、これらのゼロで埋められた領域が取り除かれ、仮想ディスクの物理ファイルサイズが減少します。

私の場合、300GBの仮想ハードディスクが5GBまで縮小されたことは、このプロセスが非常に効果的であったことを示しています。これにより、ストレージの利用効率が大幅に向上し、バックアップや移動が容易になり、ディスクスペースの節約にもなります。

Uncategorized

Posted by mamu