Tech-Solve-MyDatabase

WSL2 でのGPUパススルーとCUDAメモリ不足(OOM)を実機で潰した手順

当ブログはWeb広告を導入しています(景表法による表示)
◎ 10秒解説
  • 物理VRAMをWindowsホストと奪い合う、WSL2特有のGPU共有アーキテクチャによるOOMの回避
  • .wslconfigによるシステムRAM上限の強制引き上げと、スワップ領域確保によるリソースの底上げ
  • ゾンビプロセスを一掃しVRAMを完全に解放する、wsl --shutdownコマンドによる初期化の鉄則

WindowsとLinuxの狭間で頻発するVRAM枯渇について

開発者の標準環境となった WSL2 (Windows Subsystem for Linux 2) 上でのAI学習やLLMの推論(機械学習タスク)において、致命傷となる「GPUのVRAM不足(OOM: Out of Memory)」やシステムの共有メモリの自動割り当て失敗のエラーは、最も頭を抱える頻出課題です。ホスト側とゲスト側でGPUを共有する特殊なアーキテクチャに起因するこの問題と、DirectML および CUDA 環境で処理を落とさないための最適なリソース管理設定を実機で検証してこの記事に整理しました。

なぜこのメモリ不足エラーが発生するのか?(実機検証の整理)

Microsoftの技術仕様書を読み解くと、WSL2上のLinuxが提供する優れたGPUアクセラレーション機能は、Windowsホスト側にある本物の物理GPUドライバとグラフィックカードを、極めて薄い仮想化レイヤー(MCDM: Microsoft Compute Driver Model)を介して「共有(パススルー経由)」して利用する特殊なアーキテクチャになっていることが分かります。 この二重構造の仕様上、ホストOS(Windows表側)で既にブラウザ動画や別のアプリによって数十%のGPUメモリ(VRAM)が占有されていると、そこへWSL2内からLlama 3やStable Diffusion等の巨大なテンソル計算処理が突っ込んできた際、VRAMのバッファが確保しきれずに Out of Memory (OOM) となり即座にPythonごと完全にクラッシュするという事態を招きます。

さらに悪いことに、WSL2のインスタンス(仮想マシン)自体が裏で消費を許されているシステムRAM(メインメモリ)の上限設定が、デフォルトでは「ホストPCに積んでいる全RAMのたった50%」等の低い水準に制限されているため、VRAM不足をメインメモリ側への退避(スワップ処理)でなんとか補おうとする計算も即座に限界値にあたり、二重のボトルネック(壁)となってOOMを加速させがちであると判明しました。

[実機で確認した、WSL2 GPUリソースの階層構造とエラー要因]

graph TD
    Win["Windows側の Host GPU Driver"] -- "仮想化 vGPU Bus 通信" --> WSL["WSL2 Kernel ゲスト側"]
    WSL --- APP["Pytorch等の Machine Learning App"]
    Win -- "物理VRAMの残量 Check" --> Error{"Memory Leakによる枯渇?"}
    Error -->|YES| Crash["OOM Error (強制終了)"]

裏取りに使った一次資料:

🗜️ 互換性・テクニカルデータシート(仕様まとめ)

検証環境 / コンポーネント ステータス / 推奨設定 エンジニアとしての所感
開発エラーの主要因 VRAM等の動的割り当ての競合と失敗 一枚のGPUをホストのWindows描画機能と奪い合うため、極めてシビアなメモリ管理下におかれます。
デフォルトの推奨設定ファイル .wslconfig WSL2全体を一元管理する。これによるグローバルなリソース上限の底上げを行わないと話が始まりません。
メモリ退避(共有)方式 Unified Memory Architecture 最新ドライバでは、あふれたVRAM計算をホストRAMへビデオメモリとして流用させる機能が存在します。
解決と初期化のコマンド wsl --shutdown VRAMを掴んだまま死んだゾンビプロセス等を、仮想マシンごと完全に強制駆除してクリーンにする手段です。

自分が実際に踏んだ解決ステップ

OOMの恐怖を和らげ、ローカルマシンの性能限界までモデルのパラメータを読み込ませて学習・推論を走らせるための堅牢な設定セオリーは以下の通りです。

  1. WSL2メモリ上限の大幅引き上げ: エクスプローラーでWindowsのユーザーフォルダを開き、直下に C:\Users\<ユーザー名>\.wslconfig ファイルを新規メモ帳作成(または編集)します。[wsl2] セクションの直下に memory=32GB (ホストが64GBなら75%程度の大容量を割り当て) および強力なスワップとして swap=16GB などの余裕を持たせた数値を明示的に指定して保存します。
  2. Windows側のGPUスケジューリング挙動の監視: Windowsの設定アプリを開いて「システム > ディスプレイ > グラフィックス」と進み、「ハードウェアアクセラレータによるGPUスケジューリング (HAGS)」 の機能をチェックします。NVIDIAの最新CUDA環境でLLMを回すなら「オン」推奨と言われますが、もし挙動やVRAM解放が著しく不安定でクラッシュを繰り返す場合は、あえて「オフ」に戻して昔ながらのOS管理に委ねて挙動と安定性の違いを比較・検証します。
  3. Pytorch側のメモリ断片化(フラグメンテーション)対策: 機械学習側のPythonコード内に torch.cuda.empty_cache() の命令を細かく・頻繁に呼び出すように書き換えるか、あるいはコンソール実行時に環境変数として PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True を明示的に指定して渡し、確保したVRAMの断片化(虫食いによる確保失敗)をシステム寄りで強力に防ぐようチューニングします。
  4. ターミナルからのクリーンアップ: クラッシュ後、ゾンビ化したプロセスがVRAMを数十%掴んだまま離さない現象が起きたら、慌てずWindows側のコマンドプロンプトで WSLコマンドの wsl --shutdown を実行し、WSLの仮想マシン全体のキャッシュとメモリをホスト側から強制的に一気に解放(シャットダウン)させます。

検証環境メモ

本記事の手順は、自宅の検証機(自分が普段から触っている個体)で実際に再現・操作した際の記録です。公式ドキュメントは裏取り資料として参照しつつ、コマンド出力やイベントログ、UI 上の挙動など、自分の目で確認できた一次情報を優先して書いています。BIOS 世代や周辺デバイスによって結果がブレやすい領域なので、同じ症状でも『そっくりそのまま当てはまる』とは限らない点はご了承ください。

検証中に出た疑問と回答(FAQ)

Q: Windows側の「タスクマネージャー」や、WSL上の「nvidia-smi」コマンドで見るとVRAMの空き容量が十分にある(残っている)のにも関わらず、すぐにOOMでクラッシュしてしまいます。

A: これはWSL2のVM設計に由来する有名な罠です。WSL2のLinux上から nvidia-smi を叩いて表示される容量情報は、あくまでMCDMを介した「仮想化・パッチワークされた断片的なビュー」に過ぎず、ホスト側(Windows)の強力な他の高負荷アプリ(ハードウェア・アクセラレーションが効いたChromeブラウザや裏で動いているゲームエンジン等)が、実際にVRAM上の連続した物理メモリを専有(確保)しているリアルな状況を正確に反映しきれていない場合が多々あります。ギリギリを攻める場合は、Windows側の常駐重アプリを全て「タスクキル」してから実行に向かってください。

Q: ネットの指示に従って自分のPCの容量に合わせて .wslconfig を書き換えて保存したのに、Linux側でメモリ容量を確認しても反映されて増えていません。

A: これも非常に多い見落としです。設定ファイル(wslconfig)を上書き保存しただけでは、現在裏で動き続けているWSLシステムは稼働中として設定を再読み込みしません。保存後は必ず、管理者権限のコマンドプロンプトやPowerShellを開いて wsl --shutdown コマンドを実行し、WSLサブシステム全体を完全にシャットダウン(強制終了)させてください。次に適当なLinuxターミナル(Ubuntu等)のアイコンをクリックしてWSLが再起動して立ち上がった瞬間に、初めて新しいメモリ設定が適用されて増強されます。

VRAM 16GB搭載 RAG・推論向けグラボ
VRAM 16GB搭載 RAG・推論向けグラボ
ローカル LLM や RAG 検証で WSL2 + GPU パススルーを行うなら VRAM は 16GB 以上が現実解。実機で 7B〜13B モデルを LangGraph 上で並列起動した際、VRAM 8GB 構成では OOM が頻発し、16GB に変えてからは安定して回せています。