|
このページは大阪弁化フィルタによって翻訳生成されたんですわ。 |
カーネルのスケジューラは、プロセスの時間的な割り振りを担当してるんや。 いっぺんに、オペレーティングシステムは、プロセスを空間的にも割り振ちう、それらが 互いの作業メモリ領域に干渉せんようにせなならしまへん。 ずぅぇえええぇぇええんぶのプログラムが協調して動いてくれると仮定した場合そやけど、 そのどれかひとつにバグがあり、それによって他のプログラムのメモリ領域が カンペキに破壊されてまうような事態は望ましくおまへん。この問題を解決するために、 オペレーティングシステムが行う対処方法は、メモリ管理 (memory management) と呼ばれて おりますわ。
コンピュータ内の個々のプロセスには、そのコードを実行したり、変数を 保存したり、処理の結果を格納したりする場所として、独自のメモリ領域が 必要や。こないなメモリ領域は、(プロセスの命令が保持される)読み出し専用 領域である コードセグメント (code segment) と、(プロセスのずぅぇえええぇぇええんぶの変数が保持される) 書き込み可能な領域である データセグメント (data segment) から構成されとると考えることができまんねん。データセグメントは、文字どおり 個々のプロセスに固有の領域やけど、そやけどアンタ、二つのプロセスが同一のコードを 実行してん場合、Unix は、メモリの利用効率の観点から、そないな プロセスが、単一のコードセグメントを共有するよう調整を行おりますわ。
メモリは値段が高いさかい、効率よう利用するっちうことが大切や。ときには、マシンで 実行中のずぅぇえええぇぇええんぶのプログラム全体をメモリに保持するだけの余裕があらへん場合が 生じまんねん。特に、X サーバのような巨大なプログラムを実行してんような場合 には、メモリ不足が生じることがおます。この問題に対処するために、 Unix は、仮想メモリ (virtual memory) と呼ばれるテクニックを 使うんですわ。こら、プロセスのずぅぇえええぇぇええんぶのコードとデータをメモリ内に保持 したろとおもうもんやおまへん。むしろ、比較的少量の ワーキングセット (working set) だけを保持するようにして、 残りのプロセス状態は、ハードディスク上の スワップスペース (swap space) ちう特別な領域に置いておきまんねん。
用心して欲しいんは、前の段落で「ときには....生じまんねん」と書いた部分は、過去に おいては、「ほとんど毎日毎晩壱年中生じとったんや」と言い換えることができるゆう点 や。よりどエライ昔は、実行中のプログラムのサイズと比べてメモリのサイズが さらさら足りへんかったさかい、スワッピングは頻繁に起こっとったんや。せやけどダンさん、 メモリは今日ではごっつう安価になってて、ローエンドのマシンにすら、ごっつうの メモリが積まれるようになっとりまんねん。64 MB 以上のメモリを積んや現在の 個人用マシンの場合、X やよう利用するジョブが最初からコアにロードされた あとそやけど、そないなプロセスをスワッピングなしで実行するっちうことが可能に なっとりまんねん。
前章では、実際にちーとばかし話を単純化しすぎてしもたんや。確かに、プログラム はメモリを、巨大で平板なアドレス領域であり物理メモリよりも大きなもん であるんや、と認識してて、その幻想を支えるもんとしてディスクスワッピングが 利用されとるちうんはホンマや。せやけどダンさん、現実には、ハードウェアは異なる 五種類もん メモリを持ってて、プログラムが最高速度で実行されるようチューニングしなけれ ばならへん場合は、この五種類のメモリ間での違いは、どエライ重要な問題となるの や。マシン内で何が起こっとるんかをホンマに理解するためには、これら 全体がどないな仕組みで動いとるんかを知らなならしまへん。
五種類のメモリとは、次のようなもんや:プロセッサのレジスタ、内部(もしくは、 オン・チップ)キャッシュ、外部(もしくは、オフ・チップ)キャッシュ、 メインメモリ、およびディスクや。これだけの種類のメモリが存在するっちうことの理由 は、単純や。スピードを上げるにはお金がかかるさかいや。上記五種類のメモリは、 アクセス時間の短い順番、コストの高い順番に並んでおりますわ。レジスタメモリは、 最速かつ最も高価なもんなんやし、一秒間に十億回くらいランダムアクセスが可能や が、ディスクは最も低速かつ安価なんやし、一秒間に百回くらいのアクセスしか でけしまへん。
以下に、2000年初頭の典型的なデスクトップマシンにおける各種メモリのスピード の一覧表を記載しまっせ。スピードと容量は年々上昇し、価格は下がっていきまっけど、 メモリ間でのそれらの比例関係はどエライ安定してんと考えることができまんねん。 メモリが階層構造を持つんは、そないな比例関係が一定であるからや。
Size: 13000MB Accesses: 100KB/sec
Size: 256MB Accesses: 100M/sec
Size: 512KB Accesses: 250M/sec
Size: 32KB Accesses: 500M/sec
Size: 28 bytes Accesses: 1000M/sec
最速のメモリだけを使うてずぅぇえええぇぇええんぶを構築するっちうことはでけしまへん。 ごっつう高価なもんになりすぎるさかいや。仮に高価でへんかったとしたかて、 高速なメモリは揮発性や。ゴチャゴチャゆうとる場合やあれへん、要は、電源を切ると、せっかくの成果が 失われてしまいまんねん。したがちう、コンピュータはハードディスクやその他の 非揮発性のストレージを内蔵して、電源を切った際にもデータを保持できる ようにせなならしまへん。また、プロセッサの速度とディスクの速度との 間には、ごっつう大きな違いがおます。その中間にある三つのレベルのメモリ 階層 (内部キャッシュ (internal cache)、 外部キャッシュ (external cache) およびメインメモリ) は、基本的に、両者のギャップを埋めるために存在してるんや。
Linux とその他の Unix には、仮想メモリと呼ばれる機能が備わっとりまんねん。 仮想メモリとは、オペレーティングシステムが実際に搭載してんメインメモリ 以上のメモリを持っとるかのように振舞うゆうことを意味してるんや。 実際の物理メインメモリは、より大きな「仮想」メモリ空間の窓、もしくは キャッシュのように振る舞い、仮想メモリの大部分は実際にはスワップエリア と呼ばれるディスク上の領域に保持されはります。ユーザプログラムからは見えへん トコロで、OS は、データブロックをメモリとディスクの間で移動させ、 この幻想を維持してるんや。その結果、仮想メモリは、実メモリよりも ずっと大きいが、それほど遅くはあらへんメモリとして機能するわけや。
仮想メモリが物理メモリと比べてどの程度低速になるかちうんは、 オペレーティングシステムのスワッピング理屈が、どんだけ プログラムによる仮想メモリの利用方法に適合したもんになっとる かちうことで決まるんや。幸なことに、一定の時間間隔で見ると、メモリの 読み出しと書き込みは間を置かんとなされることが多いため、場所的に見た 場合そやけど、メモリの読み書きはメモリ空間内の特定の場所に集中するゆう 傾向がおます。 この傾向は、ローカリティ (locality) 、もしくはより正式には リファレンスのローカリティ (locality of reference) と呼ばれとりまんねん。 こら都合のええことや。メモリへの参照 (reference) が仮想メモリ空間 内の様々な場所にランダムに行われるんやったら、通常は、新しい参照のたびごとに ディスクに対する読み出しや書き込みが行われなければやったらへんし、仮想メモリは ディスクと同じくらい低速になってまうでっしゃろ。せやけどダンさん、プログラムと いうんは一定の場所で読み書きを行うゆう強い傾向 (locality) を 示すもんやから、メモリへの参照がある場合そやけど、オペレーティングシステムは スワップを行うことが比較的すないから済みまんねん。
こら、経験則なんやけど、最大公約数的にみて最も効率のよいメモリ利用 パターンちうんはどエライシンプルなもんや。その方法は、LRU もしくは 最長時間未使用理屈 ("least recently used" algorithm) と 呼ばれとりまんねん。仮想メモリシステムは、必要に応じて、ディスクブロックを メモリの ワーキングセット (working set) として取り込みまんねん。ワーキングセット 用の物理メモリが足りなくなりよったら、最長時間未使用のブロックをディスクに 書き出してしもてまんねん。ずぅぇえええぇぇええんぶの Unix や、仮想メモリを使うその他の オペレーティングシステムの大部分は、この LRU になんぼかの変更を加えた 理屈を使うておりますわ。
仮想メモリは、ディスクとプロセッサのスピードの違いを調整する第一の 連環となっとりまんねん。こら、OS が明示的に管理してるんや。せやけどダンさん、 物理メモリのスピードと、プロセッサがそのレジスタメモリにアクセスする スピードとの間には、まだ大きなギャップがおます。外部と内部のキャッシュ は、これを埋めるもんなんやし、そのために上記で述べた仮想メモリとよう似た テクニックを使うておりますわ。
物理メインメモリがディスクスワップ領域に対する一連の窓やキャッシュのように 振る舞っとるように、外部キャッシュもメインメモリに対する窓のように 振る舞おりますわ。外部キャッシュは、高速 (100M よりも速い 秒間 250M アクセス)で、 容量の小さいメモリや。ハードウェア (特に、コンピュータのメモリコントローラ) は、LRU の方法を使うて、メインメモリから取ってきた一連のデータをもとにして、 外部キャッシュ内のデータを管理しまっせ。歴史的な理由で、キャッシュ スワッピングの単位は、ページ (page) やのうてライン (line) と呼ばれとりまんねん。
せやけどダンさん、これで話が終わったわけやおまへん。内部キャッシュが、 外部キャッシュの一部をさらにキャッシュするっちうことで、アクセス速度の底上げの 最終段階を担当してるんや。この内部キャッシュは、さらに高速で容量の小さいメモリ や。事実、こらプロセッサチップのすぐ側に置かれとりまんねん。
読者がプログラムをホンマに速くしたい思うんやったら、こないな細かい事柄を知って おくことが有益や。プログラムは、ローカリティが強いほど高速になるんですわ。 キャッシュがより効果的に働くさかいや。それやから、プログラムを速くするいっちゃん簡単な 方法は、プログラムを小さくするっちうことや。プログラムがようけのディスク I/O の ために動きが鈍くなりよったり、ネットワークイベントを待ったりせえへんかて すむ場合、そら、通常、システム内で許容されとる最大のキャッシュ効果を ともなりよったスピードで実行されるはずやからや。
プログラム全体を小さくでけへん場合は、スピードに関係する部分をチューニング するようにして、強いローカリティを発揮するようにしたら報われるでっしゃろ。 そないなチューニングに関するテクニックの詳細は、この文書の範疇を越えまんねん。 読者がそれらを必要とする頃には、コンパイラにごっつう精通してんはずやから、 そないな方法はおのずと理解できるはずや。
充分な容量のコアがあり、スワッピングを避けられはるときそやけど、メモリ管理 (memory management) と呼ばれるオペレーティング システムの一部は、重要な役割を果たしてるんや。確認しておきたいんは、 プログラムはオノレのデータセグメントしか変更でけへんちうことや。 すなわち、あるプログラムの中の不具合のあるコードや悪意を持って作られはった コードが、他のプログラムのデータセグメントにデータを吐き出すことは でけへん仕組みになっとるちうことや。これを実現するために、 メモリ管理機構では、データセグメントとコードセグメントの一覧が書かれた テーブルを保持してるんや。 このテーブルは、プロセスが追加のメモリ領域を要求したり、それまで使うていた メモリ領域を開放する(通常、こらプロセス終了時に起こるんや)たびに、 更新されるようになっとりまんねん。
オペレーティングシステムのメモリ管理機構は、このテーブルを使うて、 MMU もしくは メモリ管理ユニット (memory management unit) と呼ばれる、下位層のハードウェアにある特別な箇所にコマンドを渡してるんや。 現代のプロセッサチップには、複数の MMU が内蔵されとりまんねん。 MMU は、メモリ領域を保護するための特別な機能を持っとるさかい、越境的な メモリ参照は拒否されるとともに、その際には特殊な割り込みが発生するように なっとりまんねん。
本日この時までに、"Segmentation fault" や "core dumpd" といった文句を見た ことがあるやったら、まさに、そないな越境的なメモリ参照が起こったゆうことを 意味しまっせ。実行中のプログラムがオノレ以外のセグメントにメモリアクセス したろとおもうと、致命的な割り込みが起きるちうワケや。こら、プログラムに バグがあることを意味してるんや。MMU が残す core dump は、プログラマがそのバグを追跡するんを支援するための 診断情報なんやこれがホンマに。
プロセスの相互干渉の防止は、プロセスがアクセスできるメモリ領域を分離する こと以外に、さらに別の観点からもなされとりまんねん。読者は、上記以外にも、 ファイルへのアクセス制御が出来よるようにして、バグのあるプログラムや悪意を 持ってつくられはったプログラムがシステムの重要ファイルをカンペキに破壊でけへんように したい思うことでっしゃろ。 Unix が、ファイルパーミッションちう 仕組みを持っとるんは、このためや。これについては、後ほど説明しまっせ。