VMware ESXにおけるメモリ管理(5) - 透過的ページ共有

VMware ESXにおけるメモリ管理』シリーズ
(1) - 序:他のリソースとの違いはなに?
(2) - 仮想化インフラにおけるメモリ管理って?
(3) - メモリに関する仮想化支援機能(Intel EPT/VPID, AMD RVI/Tagged TLB)
(4) - メモリを割り当てるのは簡単だが、回収するのは難しい
…の続きです。

では、メモリ管理に関する具体的な機能に入っていきましょう。1つ目は透過的ページ共有(Transparent Page Sharing / TPS)からです。
1つのESXホスト上で複数の仮想マシンを実行した場合、同一のデータが格納されたメモリページを複数の仮想マシンが使用する場合があります。特に同一のゲストOS、同一のアプリケーション、同一のデータが複数の仮想マシン上で実行されていた場合、それらのプロセスが使用するメモリページは同一である可能性が非常に高いということになります。メモリページのデータが頻繁に書き換えられている場合はともかく、OS自身のプロセスが使用するメモリページのように、一度メモリ上に展開された後は継続的に読み込まれるだけとなるメモリページについては、それぞれの仮想マシンに対してそれぞれ物理メモリからページを割り当てるのではなく、同一のメモリページを参照するようにすれば物理メモリを節約することができるという考えに基づいて実装された機能が透過的ページ共有です。その名の通り、ゲストOSに対しては透過的に実装されているため、ゲストOS側には一切の変更は必要ありません(そもそも、ゲストOSは透過的ページ共有が行われていることを一切意識していません)。
ではESXはどのようにして「同一のメモリページ」であるかどうかをチェックするのでしょうか。ESXは定期的に各仮想マシンが使用している各メモリページに含まれるデータのハッシュ値を収集して自身が管理するハッシュテーブル(Global Hash Table)で管理を行っています。

ハッシュ値はゲストOS側が物理メモリページと認識しているメモリ空間に格納されているデータを対象として算出されます。ハッシュ値は元の数値が同じでない限り同じ値となることはほぼないといえますので、その結果、「同一のハッシュ値」が生成されたメモリページには同一のデータが配置されている可能性が非常に高いということが考えられます。もちろんESXはあやまりを防ぐために、同一ハッシュ値と検出されたメモリページについてはその格納データの内容を完全に比較して同一データであることを確認した上で、透過的ページ共有による仮想マシン間でのページ共有を行います。つまり、ESXはハッシュ値を生成することによって全てのメモリページをチェックするのではなく、絞られたメモリページだけを対象とすることにより効率的な「同一のメモリページ」の検出を行う仕組みを実装しているわけです。
仮想マシン間で直接的には他の仮想マシンに影響を及ぼさないことが求められるHypervisorにおいて、透過的ページ共有を行うことは問題がないのでしょうか?透過的ページ共有は2つの理由によりその安全性が担保されています。1つはゲストOSに対しては完全に透過的にページ共有が行われているためにゲストOS側からどのメモリページが他の仮想マシンと共有されているのか確認することができないということ、そしてもう1つが、透過的ページ共有で共有されているメモリページには書き込みはできない、ということです。透過的ページ共有が使用されているメモリページに対する書き込み要求が来た場合、VMkernelは書き込もうとした仮想マシンに対してページフォルトを返すとともに書き込み対象のメモリページをCopy on Write (CoW)により用意して参照先ページを変更します。このようにして透過的ページ共有はゲストOS側には一切の修正なく物理メモリを節約することができるメリットをもたらしますが、メモリI/O性能としては書き込みを行おうとした際にページフォルトが発生する可能性がある分のオーバーヘッドを生じさせていることとなります。
VMkernelは"Mem.ShareScanTime"設定値に基づいて定期的にゲストが使用しているメモリページをランダムにチェックを行います。デフォルトではこの値は60(分)となっており、1時間おきに全メモリページのチェックが行われます。また、1秒当たりにチェックするページ数はESXホストとしては搭載CPUクロック数(Mem.ShareScanGHz、デフォルトは1GHzあたり4MB/sec)に基づいて、仮想マシンとしては1VMあたりにチェックスキャン可能なメモリページ量(Mem.ShareRateMax、デフォルトは1024)が制限されます*1

これらの詳細パラメータについては、基本的にデフォルト値の使用が推奨されており、VMwareサポートから特別な指示がない限りチューニングすべきではない項目となります。透過的ページ共有はメモリを節約して効率的に使用する方法としては有用ですが、ハッシュ値のチェックやページスキャンなどの処理のためにオーバーヘッドがありますのでESXホストは盲目的にこれらのパラメーターに従うのではなく、自律的に透過的ページ共有の有効度合いに基づいてチェック間隔を調整します。メモリページの共有があまり使用されるメモリ量の節減に効果を発揮していない場合はページスキャンの処理間隔を長めに、逆に効果的な場合は処理間隔を短めに調整することにより、ESXホストはオーバーヘッドを最小化します。
…とここまで透過的ページ共有についてご説明してきましたが、今後ESXホストでは透過的ページ共有が利用される状況は次第に少なくなっていくことになるでしょう。その理由は、ラージページが使用されるようになってきているためです。ESXホストはIntel EPTやAMD RVIなどのメモリ管理に関するハードウェア支援機能が利用できる場合でゲストOSがサポートする場合においては、自動的にラージページを使用します。デフォルトの4KBのメモリページに対して、2MBのサイズがあるラージページでは、1ページ当たりのサイズが500倍となりますのでより多くのコンテンツが1つのメモリページ内に格納されることになります。よって、当然ながら確率論的にも複数のラージページ全体が完全に同一のページコンテンツを持つ可能性はかなり低くなることとなります。また、ハッシュ値の比較はともかくとして、ハッシュ値が適合した際のメモリページの完全スキャンに要するオーバーヘッドはサイズ分(つまりは500倍)大きくなると言えます。よって、ESXホストはラージページについては透過的ページ共有の対象とはしません。ただし、各メモリページに対するハッシュ値の計算は引き続き行われます(4KB単位ずつに区切ってハッシュ値の生成が行われます)。ESXホスト上で稼働する仮想マシンにとって、最もパフォーマンスに悪いインパクトを与えるメモリ管理機能はスワップアウトです。よって、仮想マシンのメモリページをスワップアウトさせてしまうことは最も避けなければならない状態といえます。ESXホストはそのような状況となることが予見される場合においては、ラージページを通常のメモリページに分割し、事前に作成しておいたラージページの「一部分」である4KB単位のハッシュ値(=分割されたメモリページについてのハッシュ値)に基づいてメモリページの「部分」を透過的ページ共有の対象とすることによりスワップアウトを何が何でも防止しようとする仕組みは動作します。
ラージページが使用されるようになると透過的ページ共有の効率性が落ちるということについては、VMwareのみならずMicrosoftも認識しています。そのため、新興HypervisorであるMicrosoft Hyper-Vでは透過的ページ共有機能を実装せずに、"Dynamic Memory"とよばれるメモリ効率化技術をHyper-V 2.0から実装しました。次回は少し脱線して、Hyper-VにおけるDynamic Memoryがどのようにして仮想化環境におけるメモリの効率的な使用を実現しているのかについて見ていきたいと思います。

※2011/4/23に、amechikaさんにご指摘頂き一部修正しました。詳細はコメント欄のやり取りをご参照下さい。amechikaさん、ご指摘ありがとうございました。

*1:そもそもとして、"Mem.ShareVmkEnable"を無効(0)とすれば透過的ページ共有機能自体を無効化することが可能