差分

移動先: 案内検索

記憶管理

627 バイト追加, 2007年11月15日 (木) 11:28
/* 局所参照性 */
局所参照性とは「プログラムは同じ場所にアクセスを繰り返す性質を持つ」です。もしプログラムがランダムにメモリ空間をアクセスする性質を一般に持っていたならば、たぶん仮想記憶のようなシステムは無意味だったでしょう。なぜならば大量のページイン・ページアウトが発生しまうからです。このような大量のページイン・ページアウトが発生してしまう状態をスラッシングと呼びます。  しかし殆んどのプログラムは局所参照性を持つので、使われていない部分を外部に移しても全体としてみた場合、リーズナブルなパフォーマンスが得られているのです。局所参照性とは「プログラムは同じ場所を繰り返しアクセスする性質を持ちやすい」というものです。常に成立するわけではありません。もしプログラムがランダムにメモリ空間全域をアクセスする性質を一般に持っていたならば、たぶん仮想記憶のようなシステムは無意味だったでしょう。なぜならば大量のページイン・ページアウトが発生しまうからです。このように大量のページイン・ページアウトが発生してしまう状態をスラッシングと呼びます。しかし殆んどのプログラムは局所参照性を持つので、使われていない部分を外部に移しても全体としてみた場合、リーズナブルなパフォーマンスが得られているのです。
| CPU |<->|キャッシュ|<---->| メインメモリ |
+------+ +----------+ +------------------------+
 
これを一般化してみると、「データを高速にアクセスできるほど装置は容量当たりのコストが高いので、容量とコストを勘案し多段に装置を組合せることによって、リーズナブルに高速で大容量のアクセスできる記憶装置を用意することができる」ということになります。メモリ、仮想記憶、ファイルシステムなど色々な場面でこの考え方が使われます。
このアクセスが高速で小容量の装置と低速で大容量の装置との間でデータを移動させなければなりませんが、この時どのデータを選ぶかが問題になってきます。よく使われるデータは速い方へ、なかなか使われないデータは遅い方へ移すのが合理的です。ただし、「良く使われる」というのは過去の話ではなく将来の話だという所がポイントです。「良く使われるだろう」と判断するルールを決めなければなりません。このルールでよく使われるのがLRU (least recently used)です。LRUは直訳すると「最近、最も使われていないもの」ということで、簡単に言えば一番暇なものを入れ換えるという単純な話です。LinuxのページングもLRUのポリシーで行っています。
=== malloc =動的なメモリ領域確保 ==
使われていない分、実メモリが空くわけですから、その分を動的にデバイスなどへのキャッシュなどに割り当ています。そのキャッシュが大きければ大きいほど、全体のパフォーマンスはよくなります。実メモリが必要になればキャッシュに使っていた実メモリをプロセスに回します。これはLinuxだけの話ではなく、今日多くのオペレーティングシステムではこのように全体のパフォーマンスを上げるためにメモリを効率よく使うというメカニズムが取り込まれています。
 
;調べてみよう: vmstatで観察してみましょう。vmstatは仮想記憶のステータス観察するためのツールです。1秒毎に表示するオプションで動作させながら、先程のプログラムを改造し徐々に記憶を取るようなプログラムにして動かし、観察してみましょう。
...
=== mmap ===
これは今日のUnix系オペレーティングシステムでの重要なメカニズムの一つです。たとえばLinuxではプログラムを実行する時、標準ライブラリを読み込むのではなくmmapでマップします。これでファイルシステムとは違う記憶領域であるはずのメモリ内に存在するのと、まったく同じ動作ができます。動作時に実行コードをページインします。これは今日のUNIX系オペレーティングシステムでの重要なメカニズムの一つです。たとえばLinuxではプログラムを実行する時、バイナリの実行ファイルや標準ライブラリを読み込む動作をするのではなくmmapでマップします。これでファイルシステムとは違う記憶領域であるはずのメモリ内に存在するのと、まったく同じ動作ができます。動作時に実行コードをページインします。
glibcでのmalloc実装は/dev/zeroをオープンし一定領域をmmapで確保し、その領域から必要な分を切り出してプログラム側に返却しています。つまりmallocを呼び出したプログラムは/dev/zeroの領域を使っています。/dev/zeroは物理的なデバイスの実体を持たないので、カーネルが与えたメモリ空間になります。mmapはこんな使い方もされているという一例です。
この例題プログラムではマップする属性をMAP_PRIVATEとしているので、ファイルの内容を読み込みはしますが、メモリ領域に書き込んでも、それはファイルには書き込まれません。これをMAP_SHAREDとするとファイルと同期を取ることができます。このファイルを複数のプログラムからオープンすると共有メモリとして利用できます。さて、この例題プログラムではマップする属性をMAP_PRIVATEとしているので、ファイルの内容を読み込みはしますが、メモリ領域に書き込んでも、それはファイルには書き込まれません。これをMAP_SHAREDとするとファイルと同期を取ることができます。このファイルを複数のプログラムからオープンすると共有メモリとして利用できます。
;補足: 内容をアップデートして同期するにはメモリに書き込み後、msync(2)やmunmap(2)を呼ぶことが必要です。
==== 単一レベル記憶 ====
ファイルもメモリも、さらにデバイスすらも単純な1つの記憶空間として扱おうというコンセプトが単一レベル記憶です。現在、オペレーティングシステムレベルでサポートしているのはIBM社のSystem iシリーズぐらいしかないので、インターネット上で説明を探すとIBM System iの機能=単一レベル記憶の定義みたいな説明しかありませんが、実は、その歴史は古く1960年代に作られたMultics上に既に実装されています。UNIXは単一レベル記憶を前提としているデザインはありませんが、現在のUNIX系のオペレーティングシステムはmmapを実装することによってMulticsが持っていたファイルもメモリも、そしてデバイスも同様に扱うことができる利益を得ています。例としては今時のLinuxやその他UNIX系のオペレーティングシステムでは実行バイナリやライブラリを動かすとき、一々ファイルの中身を読み込む動作をせず、実行するバイナリデータを内部でマップしてしまいます。ですから古典的なUNIXで言われるような、「実行バイナリファイルをメモリに読み込み実行する」という表現は少なくとも現在のLinuxの実行時の表現としては適切ではないという状況になっています。あとデバイスの利用例としては、malloc()のいくつかの実装では内部で記憶領域を確保するとき/dev/zeroをmmapでオープンして使っています。mmapの機能の背景にある単一レベル記憶というキーワードは知っていて損はないでしょう。
匿名利用者