メモリその1

Shared Memoryの話も出たことだし、このあたりで話題をProcessからMemoryに移して見たい。いやProcessレベルでも勿論Memoryの話はあるのだが、もう少しSystem Wideな話である。話題としては「第7章 メモリ管理」(上巻P435~)に関係する部分だ。

このうち7.1(上巻P435~P443)に関しては、殆どVMSとは無関係な、Windowsで実装された機能と考えて良い。勿論、例えばメモリマネージャコンポーネント(上巻P436~)に列挙されている3項目(というか、2+6項目というか)の内部を見ると、似た機能を備えているものもある。具体的に言えば、「ゼロページスレッド」にあたるものの一部は、VMSにおいてはDemand Zero Pageとして提供されるが、その実装はWindowsと異なり、Page MappingのOptionという形で提供される。このあたり、要するにDemand Zero Page(0クリアしたページ)をハードウェアで提供できるVMSと、複数プラットフォームがゆえにそれを期待できない(ので、別Threadの形でページの内容を物理的に0クリアする処理を走らせる)Windowsでは異なって当然であり、なので余り共通点は見出せないといってよい。あるいはワーキングセットマネージャの基本的な動作は似ているが、実装という観点ではVMSと全く異なる。

VMSの場合、Working Setの調整は基本的にQuantum単位で行われる。また、Working Setの調整そのものは、各Processが自発的に行う形になる。つまりQuantumが終わってSCH$QENDが呼び出される中で、Working Setの調整を行うSYS$ADJWSLが呼び出され、ここで調整される形になる。これはバランスセットマネージャが各Processと独立に動き、勝手にFree Listのサイズを調整するWindows系と大きく異なる部分だ。

全般的に見て、このあたりはVMSから大きく設計を変えている気がする。その大きな理由は、やはりプラットフォームの違いではないか、と思う。VMSは、乱暴に言ってしまえば1種類のMMU(*1)のみを対象にMemory Managementを作ればよかったのに対し、WindowsではどんなMMUやハードウェア割り込みが来るか判らないという前提があり、かなりの部分をソフトウェアで作りこむ必要があった。VMSでは、Quantumの割り込みのタイミングでBalance Setの調整をすれば十分システム的に動作することが過去の経緯から判っていた(VMS 1.0からの蓄積というのは、こういう場面では大きい)のに対し、Windowsではそこまでの自信は無かったのではないかと思う。ただ結果として、こうした機能をKernel Serviceの一部とは言え独立したThreadに追い出したのは調整の幅を広げることになったと思う。VMSの場合、調整のタイミングはあくまでもQuantumということになるので、Balance Set Adjustmentがうまくいかない場合、Quantumを短縮するかWSINC/WSDECを大きくする形になる。ところがQuantumを短縮すればオーバーヘッドが増えるためにシステム全体のオーバーヘッドが増えやすいし、WSINC/WSDECを増やすと、こちらも結果的にオーバーヘッドが増えやすい。対してWindowsは、まずはワーキングセットアジャスタの介入頻度を増やす形で対応でき、これでも追いつかなければいよいよQuantumなりWSINC/WSDECをいじるという形にできる。この手の話はあくまでバランスであり、そのバランスをとるための手段を増やす形でインプリメントされたのは好ましいのではないかと思う。

ついでに、プロセス/スタックスワッパに関連してSwapについてちょっと説明しておきたいと思う。こちらの最後でちょろっと「VMSの場合、Page FileとSwap Fileは別に確保される」と書いた。VMSではこの両者をどう区別しているかという話だが、端的に言えばPage Fault Handlerが動く場合にはPage File、Swapperが動く場合にはSwap Fileをそれぞれ使う。両者の共通点は

  • どちらもCommon Databaseをベースに動作する。つまり、Process Page Table、Working Set List、およびPFN Databaseを参照する。
  • どちらも通常のI/O要求を使って処理が行われる。
  • どちらも、最小のI/O要求で最大のI/O処理を行おうとする。Page Fault HandlerはRead clustering(まとめての読み込み)を行おうとするし、Swapperはinswapとoutswapの両方で、なるべく少ない回数で処理を行おうとする。

といったあたりである。

(*1) 実はVAXも世代によってMMUの構造が色々変わっている。というのは、世代が進むにつれ、新しいI/O Busやマルチプロセッサ対応を割りとアドホック的に行っており、結果としてVMSのバージョンが進むにつれ、このあたりが結構ややこしい事になっている。ただこれが許されたのは、VAXシリーズを全部あわせても数十種類、動作周波数の違いなどをまとめると20種類程度だからである。なので、差分を追加モジュールの形で選択してロード、なんて形で対応が可能だった。