WindowsへLinuxソフトウエアを移植するのは面倒

ここしばらくは、「MSYS2」を使い、WindowsでLinuxコマンドを利用する方法について説明している。MSYS2の大きな特徴は、WindowsにおいてネイティブにLinuxのコマンドを利用できるという点にある。バイナリはWindows向けにビルドされたネイティブなものであり、仮想環境で動作しているわけではない。

LinuxのようなUNIX系のOSは、「POSIX」と呼ばれる互換性規格をサポートしている。サポートレベルはOSごとにさまざまだが、UNIX系OSでソフトウエアの移植が比較的容易なのはPOSIXという共通の規格が存在していることが大きい。

Microsoft Windowsも限定的にPOSIXの一部をサポートしているものの、その割合はUNIX系OSよりも少ないし、それほど積極的にサポートするという姿勢でもない。Linuxソフトウエアの多くがダイレクトにWindowsに移植されていないのには、こういった背景がある。

WindowsはWSL2でLinuxに対応

「MSYS2があるじゃないか」と思われるかもしれないが、MSYS2もLinuxコマンドを完全にWindowsネイティブに移植しているとは言い難い。Linuxソフトウエアに手を加えることなくWindowsでビルドして利用できるように、「一枚噛ませている」というのが表現としては適切だ。Windowsにはない関数を実行できるように、MSYS2のライブラリがいったん引き受けてWindowsのAPIで処理し、元のプログラムへ結果を返す、という流れになっている。

この仕組みはMicrosoftが「WSL1」(WSL2の1つ前のバージョン)で採用していたものに似ている。WSL1が使っているのは「システムコールを差し替えることで別のOSのバイナリを実行できるようにする」という互換レイヤ技術であり、WSL1以前から多くのOSで利用されてきた。MSYS2は、この仕組みと直接Windowsのライブラリをリンクするというハイブリッド的な仕様になっている。

一方、Microsoftが推している「WSL2」は、「Hyper-V」という仮想環境でLinuxを実行するというものであり、仕組みが異なる。MicrosoftはWSL2を提供することで、WindowsにおいてLinuxバイナリを100%実行できるようにし、さらにLinuxアプリケーションの開発も可能にした。POSIX互換性も、WSL2を持ち出せばLinuxと同じレベルということになる。Microsoftとしては、WindowsでLinuxを使うならWSL2を使うことを推奨する、ということになるわけだ。

Microsoftの推しはWSL2だけれど…

Microsoftの”推し”はWSL2だ。Visual StudioやVisual Studio Codeで、Linuxで動作するサーバを使ったWebアプリケーションの開発ができるようにエクステンションの開発と提供も行っている。今は、WindowsだけでLinuxサーバアプリケーションの開発ができる状態だ。

だとすれば、わざわざMSYS2を使う理由はないということになるのだが、実際にはそうはならない。単刀直入に言うと、PCのスペックが十分にあり、メモリが豊富に搭載されているならばWSL2でよいが、メモリが少ないならばWSL2以外を検討する必要がある。

WSL2はとても便利なのだが、メモリを消費しやすい仕組みである点に注意が必要だ。これは特に、開発を行っている場合などに問題となる。使っていくうちに、いつの間にかメモリを使い切ってしまい、ほかのアプリケーションや仮想環境が起動できない事態に陥ってしまうのだ。現在家電量販店やオンラインショップで購入できる平均的なPCのメモリ容量ではすぐに使い切ってしまう。

WSL2経由でメモリを使い切るサンプル

WSL2を起動した段階で消費されるメモリ量はそれほど多くない。この状態でうまく使い続ける限り、メモリが切迫することは少ない。しかし、WSL2でディスク動作を行うとガンガンメモリが消費されていく。例えば、WSL2 (Ubuntu)を起動して、次のようにddコマンドで10GBのファイルを作成してみよう。

PS C:\Users\daichi> ubuntu
daichi@XPS-13-9305:~$ dd if=/dev/random of=data.raw bs=1024x1024 count=1024x10
10240+0 レコード入力
10240+0 レコード出力
10737418240 bytes (11 GB, 10 GiB) copied, 120.946 s, 88.8 MB/s
daichi@XPS-13-9305:~$

次のスクリーンショットは、タスクバーでメモリ消費の様子を見たものだ。WSL2起動時にちょっとだけメモリ消費が増え、その後ファイルの作成を始めたと同時に消費メモリがじわじわ増えている。

ファイルの作成開始後にメモリ消費が増えていく

ファイルの作成が完了する前にWindowsの消費メモリは上限に到達している。そして、ファイルの作成が終わった後もメモリは開放されることなく確保されたままになっている。

めいっぱい消費されたメモリは確保されたまま

確保されたメモリが減ることはなく、Windows側は余裕のない状態が続く。ここで次のように明示的にWSL2をシャットダウンしてみよう。

daichi@XPS-13-9305:~$ exit
ログアウト
PS C:\Users\daichi> wsl --shutdown
PS C:\Users\daichi>

WSL2のシャットダウンが開始されると一気にメモリの開放が始まり、WSL2のシャットダウンが完了すると確保したメモリが開放される。

WSL2をシャットダウンすると一気にメモリが開放される

WSL2はシェルを抜けただけでは終了せずに動き続けている。このため、上記のように明示的にWSL2をシャットダウンしない限り、メモリは消費されたままだ。この状態でほかのアプリケーションを起動しようとしても、「メモリが確保できない」といったエラーが表示されて起動できないことがある。ほかの仮想環境を起動するとなると、かなり厳しい。

このときWindowsでは「vmmem」というプロセスが大量のメモリを確保していることを確認できる。

PS C:\Users\daichi> ps -ProcessName vmmem

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
      0 7,973.65   7,958.03       0.00    9424   0 vmmem
   3291   477.80       0.01       0.00   14108   0 vmmem

PS C:\Users\daichi>

WSL2でファイルを作成すると、Linuxカーネルがファイルの内容をキャッシュする。これはLinuxカーネルとして適切な動作であり、UNIX系OSの多くが同じ動きを見せる。可能な限りパフォーマンスを引き上げようとすれば、こういった動作になる。結果として、Hyper-Vが確保するメモリ容量がどんどん増えていき、最終的に「Windowsのメモリ不足」という状態になるのだ。

メモリが少ないPCではWSL2はちょっと厳しいかもしれない

「気づかないうちにメモリを大量消費していた」というのは、特にWSL2内部でファイルの読み書きが発生する場合に起こりやすい。

また、Visual Studio CodeやVisual StudioでWSL2を経由したLinuxサーバアプリケーションの開発を行っている場合なども、じわじわと消費メモリが増えていく。メモリが大量に搭載されたPCを使えばよいのだが、懐事情もある。

さらに言えば、今やデスクトップPCの多くがノートPCに移行している。最近のノートPCはスタイリッシュなデザインである反面、後からパーツを交換してメモリを増設するのは難しい構造になっているものが多い。メモリを増やしたければ新しいノートPCを買うしかないが、そんなに気軽に買い換えられるものではないだろう。

メモリが少ないならMSYS2も良い候補

Visual StudioやVisual Studio CodeでLinuxサーバアプリケーションを開発するのであれば、WSL2以外の選択肢を選ぶのはあまり現実的ではない。だが、Linuxコマンドが実行できればよいということならば、WSL2ではなくMSYS2を選ぶというのも選択肢になる。

MSYS2では今回説明したようなメモリの大量消費は起こらないので、搭載されているメモリ容量が少ない場合には得策となる。WSL2も特定の使い方を避ければそれほどメモリ消費が増えることはないが、それでもじわじわとメモリが減っていくのは辛い。

このように、WSL2とMSYS2は仕組みも違えば特徴も違う。競合するというよりは、適材適所で使い分けるものという位置付けになる。メモリ容量が少ないPCを使っている場合は、一度MSYS2の利用も検討してみるとよいだろう。