Microsoftは2026年7月14日、Windows Subsystem for Linux(WSL)のユーザー処理と基幹処理をcgroup v2で分ける変更を、WSLのmasterブランチへ取り込んだ。コンパイルなどでメモリを使い切ったとき、Linux側のアプリとWSLを動かす処理が一緒に倒れ、負荷が収まってもWSLが応答しなくなることがある。この連鎖を抑えるため、新設するユーザー用cgroupにはメモリとCPUの上限を設け、mini_initなどをその外側に残す。ただし、これは公開版への配布ではない。最新pre-releaseの2.9.4より後にマージされた実装であり、利用者に届く版番号と時期はまだ示されていない。
共倒れを避ける32MiBと0.01コア

今回の変更が守ろうとしているのは、メモリを大量に消費するアプリそのものではなく、WSLを動かし続けるための基幹処理だ。WSL 2の軽量仮想マシン内に/wsl-userというcgroupを作り、ユーザーが起動した処理を配下へ移す。systemd、セッションリーダー、起動時のboot commandも同じ制限を受ける。ディストリビューションに属さないプラグイン処理はnon-distroグループに入る。
一方、mini_init、GNS、Plan9、WSL initといった処理は、上限を設定しないroot cgroupに残る。mini_initはWSL 2の各ディストリビューションを起動し、VHDのマウントやnamespaceの作成を担う処理だ。ここまでユーザー負荷に巻き込まれると、メモリを消費したアプリが終了した後も、WSLがエラー状態から戻れなくなる。基幹処理を別の資源枠へ退避させることが、今回の設計変更の中心である。
/wsl-userのmemory.maxには、Linuxのsysinfoが返す仮想マシン内の総メモリから32MiBを引いた値を設定する。上限に達して使用量を下げられない場合、cgroup内のOOM killerがユーザー処理を終了させる。基幹処理は対象グループの外にいるため、障害処理や通信を続ける余力が残る。どのアプリが終了するかを固定する仕組みではないが、WSL全体が応答を失う連鎖は起きにくくなる。
CPUも同じ考え方で分ける。実装は100,000マイクロ秒の周期に対し、仮想マシンへ割り当てられた全論理CPUの総時間から1,000マイクロ秒を差し引いてcpu.maxへ書き込む。基幹処理に残すのは0.01論理コア相当と小さい。それでも、ユーザー処理が全CPUを埋めた場面でmini_initなどをスケジュールする逃げ道になる。
発端になったGitHub Issueでは、Vulkan SDKをninjaでビルド中にWSL 2.6.3.0が突然終了する事例が報告されていた。報告者は2台のWindows 11 PCで経験したとしている。ただし、WSL側はこの現象を非決定的で再現が難しいと記録しており、元のOOM事例を固定条件で再現する自動テストは追加していない。今回の設計は障害経路を狭めるが、重負荷時の停止を一切なくす保証ではない。
Windows側の上限とWSL内部の上限は役割が違う
WSL 2には以前から、Windowsのユーザーフォルダに置く.wslconfigでメモリ量と論理プロセッサ数を制限する機能がある。公式文書によると、memoryの既定値はWindowsに搭載した総メモリの50%、processorsはWindowsと同じ論理プロセッサ数だ。ここで決めるのは、WSL 2の仮想マシン全体へWindows側から渡す資源量である。
新しいcgroupは、その割当枠の内側をさらに二つに分ける。違いは次のようになる。
| 境界 | 設定する場所 | 対象 | 目的 |
|---|---|---|---|
| WSL 2仮想マシンの割当 | Windows側の.wslconfig |
仮想マシン全体 | WSLがWindowsから使えるメモリとCPUを決める |
/wsl-userの上限 |
WSL内部のcgroup v2 | ユーザー処理の合計 | WSL基幹処理のために32MiBと0.01コア相当を残す |
distro-<init pid> |
/wsl-user配下 |
各ディストリビューションの処理 | systemdのcgroup階層を互いに分ける |
つまり、32MiBをWindowsホスト全体から新たに確保するわけではない。.wslconfigでWSL 2のメモリを任意の値に制限していれば、新しいmemory.maxはその仮想マシン内で見える総量を基準に計算する。WindowsとWSLの境界を広げる変更ではなく、与えられた枠をユーザー負荷が最後まで使い切れないようにする変更だ。
この区別は運用にも効く。従来は.wslconfigのメモリ上限を下げればWindows側への影響を抑えられたが、上限に達したWSL内部では基幹処理も同じ圧力を受けていた。新実装が入れば、Windowsを守る外側の上限と、WSL自身を生かす内側の上限を別々に持てるようになる。
複数ディストリビューションのsystemdを分ける
もう一つの変更は、各ディストリビューションに/wsl-user/distro-<init pid>というcgroupを割り当てることだ。systemdを有効にした環境では、さらにsystemdとnon-systemdの子グループを作る。WSLの公式技術文書によれば、各ディストリビューションは別々のmount、pid、UTS namespaceで動く。ところがcgroupの階層は十分に分かれておらず、複数のsystemdが同じパスを使おうとして衝突することがあった。
実際、WSL 2.7.3.0の利用者からは複数のUbuntu環境を起動した際、一部でsystemdのユーザーセッションが始まらないとの報告が出ていた。ログにはDevice or resource busyが残り、user@1000.serviceをcgroupへ接続できなかった。また、WSL 2.7.8.0ではDebianとUbuntuを同時に動かすと、Debianのpoweroffが終わらない事例も報告されている。
ディストリビューションごとにcgroupの根を分ければ、一方のsystemdが作った階層を他方が取り合わずに済む。PRではUbuntuとDebianを同時に起動する手動確認に加え、systemdの有無、分離機能を無効にした場合を含むcgroup配置の単体テストが追加された。終了したディストリビューションのcgroupを削除し、古い階層が残らないことも検査している。
ただし、各ディストリビューションへ32MiBずつ予約する実装ではない。メモリとCPUの上限は上位の/wsl-userに置かれ、全ユーザー負荷で共有する。distro-<init pid>が解決するのは主に階層の衝突であり、ディストリビューション別の資源保証ではない。
2.9.4には未収録、cgroup v1利用者には退路
PR #40519は日本時間7月14日13時10分にmasterへマージされた。同日6時06分に公開されたWSL 2.9.4はpre-releaseで、変更一覧にこのPRを含まない。Microsoftは次のpre-releaseや安定版へ入る時期を示しておらず、現時点で一般利用者がwsl --updateを実行しても新しい保護を使えるとは限らない。
互換性にも条件がある。新しい階層はcgroup v2を使うため、cgroup v1を必要とする古いワークロードとは両立しない。実装は.wslconfigの[wsl2]にisolateDistroCgroup=falseを設定すれば分離を無効にできるようにした。既定値はtrueである。無効にすればcgroup v1を維持できるが、OOM時に基幹処理を守る資源枠と、ディストリビューション別の階層も同時に失う。
また、cgroup controllerの有効化やプロセスの移動に失敗した場合、実装はログへ警告またはエラーを残して処理を続ける。保護機能が一部働かない状態も想定されている。配布版が出た後は、/sys/fs/cgroup/wsl-userが作られるか、既存のコンテナやsystemd運用に影響がないかを確かめる必要がある。版番号に加え、重負荷後もWSLの制御経路が応答を保てるかどうか。それが、この変更の成否を判断する材料になる。