プロセスその12

そこで、こうしたFile Mappingは原則としてPrivate Sectionに割り当てることにした。これにより、Page OutとかProcessのSwap Out時に無駄にデータが格納されたりすることを避けられる。またPage Outされないから、MappingしたFileへのアクセスは引き続き高速に保たれる事になる。

この方式の欠点は、巨大なファイルをMappingすると、その分Pagingに使えるメモリが減ってしまうことである。実は最近の水準で考えると、これは非常にシビアな問題である。なんせHDD 1台で500GBだの1TBだのといった時代だから、ファイルサイズが1GBを越えるなんてケースは決して珍しくない。こんなものをMappingしたら、あっという間にメモリを使い切る。ところがVMSのこの時代は、HDD全体の大きさが数十MB~数百MBというオーダーであり、ファイルサイズにしても1MBなんていうと巨大な方だった。勿論例外はあって、データベースなどはGB近いオーダーのものも存在したが、これをMappingしようなんて人は居なかったわけで、結果としてこの制約はそれほど問題にはならなかった。

ところで何で原則としてPrivate Sectionかというと、これは排他制御に関係してくる。複数のユーザーが同時にファイルアクセスしようとした場合、File Systemの管理下であればこれは適切な排他制御が行える。ところがGlobal SectionにMapした上で、これを複数のユーザーが同時アクセスした場合、これはメモリだから何の問題もなくアクセス出来てしまう。これを解決するためには適切な排他制御を組み込んでやる必要があるが、これをメモリアクセスそのものに組み込むのは難しい。具体的にはある種のAPI(Put/Getなど)を経由してメモリをアクセスする形で制約するしかないが、こんな事をしたら折角のメリット、つまりメモリとしてアクセス出来るからオーバーヘッドが少ないという点を潰してしまうことになる。かといって、メモリアクセスとは別に調停機構を用意したところで、それを使われなければアウトである。そのあたりを考えて、原則としてPrivate Sectionにマップし、複数プロセス間でデータを共有したければ、それはプロセス間通信を使って共有メカニズムを作る形で、とにかくMappingしたエリアにアクセスできるのは1プロセスとしたかったのだと想像される。

図1:単純な割り当て

ただ原則というからには例外がある。それは、たとえばライブラリをマッピングする場合だ。このライブラリをどうマップするか、というのは仮想記憶にとってちょっとばかり厄介な問題であった。たとえば図1の様に2つのプロセスが各々独自のプログラムを実行している事を考える。ところがそのプロセスが標準的なライブラリ(Cのランタイムライブラリなどがその代表例だろう)を呼んでいる場合、何も考えずにベタで構成すると、同じ内容のライブラリがメモリ中に二重にロードされてしまうことになる。そこで、もう少し賢くマッピングしようということで、共有ライブラリが考え出された。要するライブラリをロードしたメモリを、複数のプロセスで共有してMappingすれば効率が良いという話だ(図2)。ライブラリなら書き換える必要はないからRead OnlyとしてMapできるので、アクセスの調停を考える必要はないから、これは非常に有効な案である。

図2:共有ライブラリ

さて、問題はこのライブラリをどこに置くか、である。これをPaging Memory上に置いた場合、ちょっと厄介な事になる。まずそのLibraryはどのProcessのWorking Setに属するかが面倒な事になる。適当なProcessに割り当てて、そのProcessがPage Outされたり、Swap Outされたりすると、いきなり共有ライブラリがPage File/Swap Fileに退避されてしまいかねない。こんな事になったら、そのライブラリを待っている全てのプロセスが一斉にPage In待ちに陥ってしまう。ところがPage InするのはLibraryを所有するProcessの作業であり、これがSwap Outされてしまった日にはなかなか回復しない。もっと怖いのは、そのProcessが終了してしまうことで、そうなると共有ライブラリをMapしていた他のProcessがいきなりAccess Violation(Windows風に言えばGPT:General Protection Error)を起こしてしまう。勿論、PageにReference Count(そのページを参照しているProcessの数)を付加して、これが1以下でなければPage Outとか破棄をさせないという実装もあるが、Page Outはともかく破棄に関しては、元Processが終了した後は所有者なしの状態でPageだけ残る事になる。これはメモリ管理上、好ましくない。

ではいっそ、共有ライブラリを管理するDummy Processを作ってこれが所有すれば...という案もあるが、問題はこのProcess、自分では一切動かないことである。従ってPagingの際に説明したPage Outのメカニズムに真っ先に引っかかって直ぐにPage Out、やがてSwap Outするのは明白である。ではそのProcessに特殊なフラグを立てて、絶対Page Out/Swap Outさせなければいい、となるわけだが、そんな面倒な事をするくらいなら、はじめからPaging対象外に置けばいいことになる。(続く)