WSLがエクスプローラーを立ち上げるだけで立ち上がるのをやめたい人へ

wsl --shutdown で WSL を止めたはずなのに、数分ないしは数秒後に wsl --list --verbose を見るとディストリビューションが Running に戻っちゃう現象に遭遇しました。んで、タスクマネージャーでは VmmemWSL がメモリを大量に持っていっちゃって、昨今枯渇しがちなメモリがさらにしんどい状態に......。

というわけで調べました。

環境

項目 内容
OS Windows 11 Pro(ビルド 26300)
WSL 2.9.3.0(カーネル 6.18.35.2-1、WSLg 1.0.79)

起動のイベントログ

起動の履歴はイベントログから取れます。WSL 2 の VM は Hyper-V の仮想マシンなので、起動と停止が Hyper-V 側に記録されてます。

Get-WinEvent -FilterHashtable @{
  LogName = 'Microsoft-Windows-Hyper-V-Worker-Admin'
  Id      = 18500, 18508
} | Sort-Object TimeCreated | Select-Object TimeCreated, Id, Message
# 18500 = VM の起動 / 18508 = VM の停止

自分で wsl を打った覚えのない時刻に 18500 がずらっと並んでたら、同じ症状です。ほかの Hyper-V の VM も同じログに出るので、Message の VM 名で見分けます。私の環境だと WSL の VM は名前が GUID で出てました。

イベントログの時刻だけでは誰が起こしてるのかまでは分かりません。

犯人はエクスプローラー

犯人はエクスプローラーでした。ファイルを1つも触ってなくても、エクスプローラーのウィンドウを開くだけで WSL のディストリビューションが起動します。フォルダーを開いてから VM が落ちるまでは、こういう流れでした。

エクスプローラーがネットワークプロバイダを列挙する(WNet 経由)
  └→ Plan 9 リダイレクタのサービス P9RdrService が起動する
      └→ WSL のサポート DLL(wslsupport.dll)を読み込んで、ディストリビューションをブートする
          └→ vmwp.exe(Hyper-V の VM プロセス)→ vmmemWSL → ディストリビューションが Running になる
              └→ 誰かが起動して使っているわけではないので、vmIdleTimeout(既定60秒)で停止する

ネットワークプロバイダという仕組み

Windows にはネットワークドライブやネットワークパスの面倒を見る、ネットワークプロバイダという仕組みがあります。SMB や WebDAV もここの住人であるように、WSL も \\wsl.localhost\(昔の \\wsl$\)をエクスプローラーから見せるために、P9NP というプロバイダを登録してます。レジストリを見るとこう並んでます。

HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
  ProviderOrder = RDPNP,LanmanWorkstation,webclient,P9NP

HKLM\SYSTEM\CurrentControlSet\Services\P9NP\NetworkProvider
  Name         = Plan 9 Network Provider
  ProviderPath = C:\WINDOWS\System32\p9np.dll

Plan 9 は OS の名前で、そのファイル共有プロトコル 9P を WSL 2 が Windows と Linux の間のファイルのやり取りに使ってます。P9 と付くものは全部 WSL の 9P まわりの部品で、P9NP がプロバイダ本体(p9np.dll)です。

エクスプローラーはフォルダーウィンドウを開くと、登録されてるプロバイダを WNet という API で順番に呼びます。この列挙が P9NP に届くと P9RdrService が起きます。P9RdrService はリダイレクタ(ネットワークの向こうのファイルをローカルのファイルみたいに見せる部品)のサービスで、カーネル側には P9Rdr というドライバ(p9rdr.sys)が付いてます。このサービスが \\wsl.localhost\ の中身を答えるために、ディストリビューションまで起こしてしまう。これが毎回起きてました。

サービスの説明文がそのまんまで、「Plan9 ファイル サーバーのトリガー開始を有効にします」と書いてあります。トリガー開始というのは、誰かが必要としたときに自動で起こす仕組みです。

中身を答えるためだけに 8GB 枠の VM を起こす必要があるかというと、まあ......。設定ミスとかではなく、WSL を入れた Windows なら標準でこうなるのかなと。

実験で確かめた

p9np.dll をロードしてるプロセスを、全プロセスの Modules を舐めて数え上げました。

foreach ($p in Get-Process) {
    try { $m = $p.Modules } catch { continue }
    if ($m -and (($m | ForEach-Object { $_.ModuleName }) -contains 'p9np.dll')) {
        "[$($p.Id)] $($p.ProcessName)"
    }
}

出てきたのは explorer.exe の1つでした。権限の関係で読めないプロセスは catch で飛ばしてます。そこから両方向で確かめてます。

操作 p9np.dll のロード WSL の起動
エクスプローラーを再起動して、ウィンドウを開かない なし 7分待っても起動しない
フォルダーを1つ開く explorer.exe にロードされる 5秒で起動
ナビゲーションウィンドウの「Linux」を開く explorer.exe にロードされる 3秒で起動
P9RdrService を無効化してフォルダーを開く explorer.exe にロードされる 90秒待っても起動しない

サービスを無効にしても p9np.dll のロード自体は起きます。連鎖がサービスのところで切れてます。

P9RdrService を止める

悪人が分かったのでサービスを無効化しましょう。

まず同じ原因か確かめる

読み手さんの環境で無効化する前に、本当に同じ原因かどうかを調べてみてください。起動の履歴はさっきのイベントログで取れますし、さっきのスクリプトで explorer.exe が出てくればこの記事と同じ構成です。ここまでは状況証拠なので、最後は実際にフォルダーを開いて WSL が起きるかどうかを見ます。

  1. wsl --shutdown で止める
  2. wsl --list --verbose で全部 Stopped になってることを見る
  3. エクスプローラーでフォルダーを1つ開く
  4. 数秒待って wsl --list --verbose を見る

Running に戻ってたら同じ症状です。

無効化する

管理者権限の PowerShell から打ちます。

sc.exe config P9RdrService start= disabled

start= の後ろの半角スペースは sc.exe の構文で必須です。

設定は次にサービスが起きようとしたときから有効になるので、いまの状態も見ときます。

Get-Service P9RdrService | Select-Object Status, StartType

StartTypeDisabled になってれば設定は済んでます。StatusRunning のままだった場合、sc.exe stop P9RdrService で止められるはずですが、私は打ってないので、確実なのは OS の再起動です。

止まったか確かめる

さっきの再現手順をもう1回やって、フォルダーを開いても Running に戻らないことを見ます。私の環境では無効化して6日経ちましたが、OS の再起動を挟んでも、イベントログに WSL の VM 起動は1件も残ってません。

戻す

戻したくなったら手動起動(demand)に戻します。

sc.exe config P9RdrService start= demand

注意点

wsl.exe から使う分には影響ありません。wsl -d kali-linux -- echo ok みたいなのは無効化後も普通に動きます。Linux 側から /mnt/c で Windows のドライブを見る経路も別物(wslservice が提供する 9P 共有)なので、こっちも影響ありません。

気にするなら \\wsl.localhost\ の UNC パスです。無効化した直後のセッションではアクセスできたんですが、OS を再起動した後は p9rdr.sys がロードされてるところまでしか確認してません。エクスプローラーから WSL のファイルを頻繁に触るなら、ダメだったときに start= demand で戻す前提になります。ナビゲーションウィンドウの「Linux」ノードを無効化後に開いたらどうなるかも試してません。

まとめ

  • wsl --shutdown しても WSL が勝手に Running に戻るなら、エクスプローラーのネットワークプロバイダ列挙を疑う
  • 起こしてるのは Plan 9 リダイレクタのサービス P9RdrService で、WSL を入れた Windows なら標準でこうなる
  • 対処は P9RdrService の無効化で、戻すときは起動種別を demand に戻す
  • wsl.exe/mnt/c には影響しない。\\wsl.localhost\ は再起動後の動作を確かめてから使う

おまけ:試して駄目だったもの

P9RdrService の無効化にたどり着く前に試して、駄目だったやつです。どっちも元に戻しました。

「Linux」ノードを隠す

HKCU\Software\Classes\CLSID\{B2B4A4D1-2754-4140-A2EB-9A76D9D7CDC6}System.IsPinnedToNameSpaceTree(DWORD)を 0 で置きます。これでナビゲーションウィンドウから「Linux」は消えますが、フォルダーを開いたときのプロバイダ列挙は変わらず走るので、WSL は普通に起動しました。

ProviderOrder から P9NP を外す

ProviderOrder から P9NP を消すと p9np.dll はロードされなくなりました。それでもフォルダーを開くと WSL は5秒で起動しました。エクスプローラーは P9NP を通らない別の経路でも Plan 9 リダイレクタにたどり着くようです。