WSL2のVmmemの暴走について

投稿日:

良くある事例のひとつだが、自分の場合に起きていたことのメモ。結論としてはメモリ喰いすぎ問題のようだった。

Symptom

  • WSL2 を利用している
  • wsl.exe が応答しない (WSL2の端末が開かない)
  • Vmmem プロセスが大量のメモリを確保している
  • Vmmem プロセスが高CPU使用率を維持している

Background

まずWSL2の重要な仕様として、 「WSLインスタンス用のメモリ領域は動的に確保される」 という仕様がある

WSL 2 のメモリ使用量は、使用時に拡張および縮小されます。 プロセスによってメモリが解放されると、それは自動的に Windows に返されます。
ただし現在、WSL 2 では、WSL インスタンスがシャットダウンされるまで、メモリ内のキャッシュ ページが解放されて Windows に戻されることはありません。
https://learn.microsoft.com/ja-jp/windows/wsl/compare-versions

WSLインスタンスのLinuxは、メモリを確保しようと思えば(Windowsが設定する上限の範囲内で)自由に確保することができる。そして上記に従えば、Linux上のプロセスがメモリを解放すればWindowsに空きメモリが返還されるようだが、事はそう単純ではない。

WSLインスタンスには、デフォルトでメモリ使用量の上限値が設定されている (ref: https://taktak.jp/2022/05/21/4422/) 。WSLインスタンス上のLinuxカーネルから見ると、このWindowsが設定したメモリ上限値こそが全メモリ容量として認識される。そしてLinuxカーネルにとって空きメモリは 活用すべきリソース であるため、通常は ディスクキャッシュなどの形で積極的に空きメモリ空間を利用する 。つまりWSLインスタンスを起動し続ける限り、Windowsが設定したメモリ上限に向かってVmmemのメモリ使用量が増加し続ける。

そしてLinuxカーネルが(主観的な空き領域から)メモリを割り当てようとしたものの、実際には(ホストのWindows上では)空きメモリが枯渇しており、メモリの割り当てが履行されないシチュエーションの場合に冒頭の症状が発生しているように見える。

Resolution

現在のところ、WSLインスタンスで利用するメモリ領域の上限を設定するのが最も適切な対策のようだ。上記のrefを参照して設定すればいい。

実用上、WSLインスタンスに割り当てるメモリは最低1GBは必要に見える。512MBでDebianを運用しようとしたところ、稼働2日目に冒頭と全く同じ事態が発生した。恐らくメモリ不足でOoMを繰り返していたか、何か必要なプロセスが死んだかと思っている。現在1GBで運用しているが、問題は発生しなくなった。

そもそもメモリ不足を疑ったきっかけは、WSLではなくHyper-Vを用い、さらに動的メモリ機能を利用してLinuxを起動していたところ、同じようにVmmemが暴走(高メモリ・高CPU)を起こしたことだ。この場合はdmesgやjournalctlにOoMなどのログが残っていたので、メモリに意識を振り向けることができた。

しかしWSLインスタンスではカーネルログを保存するデーモンが起動していないので、事態の切り分けを面倒にしている。せめて dmesg のログが常に取れていれば、切り分けも楽にできるのだが......

Approx

しかし「Linuxが通常通りmallocを試行したものの、しかしWindows側においては既にメモリがExhaustしていた場合」は、Linuxから見て具体的にどういった挙動になっているのか。とても気にはなるが、今のところ調べるほどの気合いは入らない。単にmallocが失敗したりする訳ではない気がするが(そもそもカーネル内にそんな状況を想定してmallocが失敗するフローがあるのか分からん)(そしてmallocが失敗した場合のリカバーを各プロセスがどうするのかと言われても分からん)。仮にRTOSであればmallocも規定時間に則りタイムアウトして然るべきだが、果たして。