OS/2の基礎知識
第2部


各章の題名をクリックすると、目次に戻ります。

目次

ディスクキャッシュ

ディスクファイルはサイズ固定(PCでは512バイトが典型)のブロック(訳注:セ クタ)からできている。アプリケーションはブロックサイズより小さいレコードを 扱うのが普通である(訳注:これはプログラマの考え方による。ディスクの読み書 きは遅い操作なので、大きなレコード単位にI/Oを行う、というのはDOS時代には良 く行われたことである)であり、一つのブロックには複数のレコードないしレコー ドの一部分が通常含まれる。このようにディスクファイルの操作では同じ ブロックの操作が連続することが極めて多い。

同じことは、ディスクの「家計簿情報」にも言える。例えば、あるプログラムが今 特定のディレクトリからファイルを読んだとすると、後にも同じディレクトリから ファイルを読むことは極めてありうる。

ディスクキャッシュ cache は主記憶の一部で、ディスクの一部のブロックを保持 している。あるブロックが要求されると、まずそれがキャッシュにあるか検査し もしあれば低速なディスク操作を避けるようにする。ブロックがキャッシュにな ければ、ディスクから読み込むと同時にキャッシュにもそれを置く。キャッシュ が一杯なら、古いブロックが捨てられる。通常ある種の「least recently used」 (訳注:訳語を忘れた(^^;。「最近一番使われていない」、という位の意味」) 算法が使われる。これは長時間使われていないブロックを捨てる方法である。

高級なキャッシュでは、しばしばある種の「先読み」が行われる。今ファイルの 第Nブロックを読んでいるとすると、直ぐにN+1番目のブロックが必要になるだろ う。そこでCPUの空時間を利用して、ファイルシステムはこのブロックも読んで おく。時にはN+1番のブロックは使われないかもしれない。この場合先読みは無 駄になる;しかし平均的には、このアプローチで節約できる時間は偶に起きる無 駄を上回る。

ディスクを読んでいるだけで書き込まなければ、キャッシュの内容はディスク上 の内容と同一である。書き込みを始めると、そうはいかない。キャッシュの書き 込み操作には2つの一般的な方法がある:

遅延書き込みは速度的には優れているが、あるリスクを持っている:停電やシス テムクラッシュがあると、変更の一部はディスクに書き込まれないで終わってし まう。ユーザファイルの更新がおかしくなったのなら被害は比較的軽い。INIファ ィルの情報や、ディレクトリ、FATなどの更新に失敗すると被害はより重大であ る。最悪の場合には、ディスクがめちゃくちゃになって、再起動もできなくなる。

[Windowsを使っていたころは、危なくて遅延書込みを使えなかった。ディスク の異常が、アプリケーションがシステムをクラッシュさせる毎に段々悪くなって 行ったからだ。今ではOS/2を使っており、通常遅延書込みを生かしている。アプ リケーションがおかしくなっても、普通システム全体が落ちることがないからだ。]

驚いたことに、OS/2をきちんと遮断せず、電源を切ってしまう人がいるらしい。 こういった人は遅延書込みを生かしてはいけない。(本当は、こういった人を 計算機がある部屋に入れてはいけない - でもこれは別の話である。) 遅延書き 込みは、保安が速度より重要な場合もオフにすべきである。

システムがロックアップして遮断操作が困難な時(訳注:PMは比較的脆弱なので、 いかれたPMアプリを走らすと偶にこうなる)、Ctrl-Alt-Delを使ってシステムを 止めるべきである。(一度でうまくいかなければ、何秒か待って再度試みられた い。2度目は普通うまくいく。) これは正しい遮断ではないが、少なくとも キャッシュをフラッシュ(訳注:遅延書き込みで溜まっているセクタを書き出す こと)してくれる。

理屈はこの位にして、ユーザが制御できるキャッシュのパラメタを見ていこう。

DISKCACHE

DISKCACHE はFAT区画のキャッシュサイズを制御する。FAT区画が一つでもあれ ば、CONFIG.SYSに次のような行がないといけない
  DISKCACHE=3328,LW,128,AC:CD
パラメタの意味は以下のようである。 本当かどうか知らないが、DISKCACHEはディスケットには効果がないと聞いた ことがある。

註釈:多くのOS/2ユーザが、DOSとの互換性のためにFAT区画をおいている。 しかしその場合でももっとも重要なファイルはHPFS区画においている。実際 にはFATのファイルをそんなに頻繁には使わないということである。このよう な場合DISKCACHEは小さめにしておくか、止めてしまうかするのがいいかもし れない。FATの操作は遅くなるが、それより主記憶が空くので他の動作が速く なる。

IFS=HPFS 行のパラメタ

これはHPFS用である。HPFSを使っているなら、CONFIG.SYSに次のような行が あるはずだ。
   IFS=F:¥OS2¥HPFS.IFS /CACHE:2048 /CRECL:64 /AUTOCHECK:EF
CACHEパラメタはキャッシュサイズをキロバイト単位で指定する。CRECLパラメ タはキャッシュを行う最大レコードサイズをキロバイト単位で指定する。(こ れより大きなデータを一度に読み書きした場合、キャッシュはバイパスされる。) AUTOCHECKは不正な遮断が起きた後で検査すべき区画を指定する。全てのHPFS区 画を指定すべきだ。OS/2をいかれたファイルシステムで動かそうとするのは、 危険であるから。

その行に/F:2のようなパラメタがあるかも知れない。これはCHKDSKの検査レベル を指定する。デフォルトは2であり、これはほとんどの場合最適である。

CACHE.EXE

CACHE.EXEではHPFSキャッシュのパラメタを若干詳細に決められる。CONFIG.SYS からもSTARTUP.CMDからも、それがまずければ起動後にコマンドラインからも、 これを走らすことができる。これを実行しなくてもキャッシュは動作するが(そ れはIFS=HPFS行で指定されるからである)、タイミングはデフォルトのままであ る。

CACHEコマンドをパラメタなしで実行すると、現在のパラメタを表示する。典型 例を挙げよう:

            DiskIdle:     1000 milliseconds
              MaxAge:    30000 milliseconds
          BufferIdle:    10000 milliseconds
          Cache size:     2048 kbytes
  3 Lazy write worker(s) are enabled.
  1 Read ahead worker(s) are enabled.
キャッシュサイズと「ワーカ」の数は意味が明らかだろう。3つのタイミング 値は更に説明しないとよく判らないだろう。 オンライン文書によるとDiskIdleはBufferIdleより大きくないといけない、と なっているが、これは誤記であろう。

IFS=CDFS 行のパラメタ

CD-ROM用である。興味があるならオンライン文書を参照せよ。ほとんどの人に はCD-ROMの効率はシステム全体の性能には大した影響がないので、大きなCD- ROMキャッシュは不要であろう。導入時に選択された値で我慢できるかも知れ ない。

CONFIG.SYSのBUFFERS

これは512バイト単位で、実行中のI/O操作をバッファする主記憶の量を決める。 ディスクキャッシュとは異なったもので、キャッシュを止めても存在する。こ はパイプライン内のデータだと思ってよい。
   Disk <--> cache <--> buffers <--> application software

CPUキャッシュ

キャッシュは速度の違いがある場合には常に意味を持つ。ディスクキャッシュ を使う理由は、主記憶がディスクに比べ圧倒的に高速だからである。現代の CPUでは、主記憶自体がボトルネックになっている。主記憶はCPUがデータを 生成し、消費する速さに追いつかないのである。このような状況では、CPU と主記憶との間にキャッシュを入れることに意味がある。物理的には、この キャッシュは超高速なメモリブロックに、それをキャッシュとして機能させ るための金物を組み合わせただけのものである。このメモリは通常の主記憶 よりビット当たりの単価が高いが、そんなに大量はいらない。

オリジナルの8086は通常のメモリに比べ特に速いわけではなかった。そこで キャッシュは必要なかった。(内部的には命令パイプラインを持っており、 それをキャッシュの一種として考えることもできる。しかしそれはわずかに 数バイトに過ぎない(訳注:プリフェッチキュー prefetch queue))。後の 80x86ファミリは高速で、内部キャッシュを持っている。即ち、キャッシュは CPUチップの一部として実装されたのである。CPUが新しいほど、チップ上の キャッシュは大きい。

極めて高速なCPUでは、チップには載せられないくらい大きなキャッシュが 必要である。(おっけぇー、正確には必要というわけではない; でもあるとなしとでは大違いである。) マザーボードのメーカは今では「2 次キャッシュ」を載せており、これはチップ上のキャッシュ(訳注:「1次 キャッシュ」)を大きくる効果がある。チップ上のキャッシュと違うのは、 2次キャッシュはCPUチップでなくマザーボードに載っていることである。 (訳注:内蔵キャッシュの方が、ずっと速い)

[註釈:ハードメーカはしばしば販売している金物を真のマルチタスクソフト ウェアでテストしていない。つまり金物はメーカが思うほど速く動作しないこ とがありうる。その結果、OS/2は時々2次キャッシュを搭載した金物に導入で きないことがある。一旦2次キャッシュを不可にしてOS/2を導入し、その後2 次キャッシュを生かす(BIOS設定で出来る)とうまくいく。]

ディスクキャッシュと違い、CPUキャッシュはソフトウェアでは制御されない。 金物だけで制御されている。必要な金物は全部PCが持っており、ほとんどの ユーザは気にしないでいい。

主記憶を増やすとシステムが遅くなることがある。(普通はメモリを増やすと システムが速くなる。) 何が起きているかというと、追加したメモリがキャッ シュされないのである。この問題を解決するには主記憶全体をキャッシュでき るよう金物を設定する必要がある。典型的には2次キャッシュの容量を増やす ことになる(訳注:TAG RAMも増やさないといけない。)

セグメンテーションとページング

セグメンテーションはメモリ管理のハード構成法で、プログラムを他のプログ ラムから保護することができる。また(ある程度まで)自分自身から。実装は 次のように行われる。プログラムは他のプログラムに属するメモリセグメント を、共有可能なように特別に設定しない限り、読み書きできないようにする。 更に、読みだし専用セグメントに書き込んだり、コードセグメントを変更した り、データセグメントでコードを実行したりすることを、ハード的に禁止する。 80x86では、コードの呼び出しができる場所や(訳注:例えばOSの内部を勝手に 呼び出したりできない。一定の方法に従って - APIを使って - 呼ぶ必要があ る)、「危険な」操作、例えばI/Oポートの直接操作を実行できるコードセグメ ントを制限することができる、特権レベルの管理を有している。

ページングは別のハードウェアレベルでのメモリ管理法である。これはディス クスワップ(後述する)を主な目的としている。ページングの金物には普通あ る種の保護機構も含まれる。例えばあるページを読みだし専用にする、などで ある。しかしセグメンテーションほど完全な保護はできない。

80x86ファミリで初めてセグメンテーションの金物を備えたのは80286であった (時々8086にもセグメンテーションがあったと言われるが、それは言葉の濫用 というものである。セグメントによるアドレッシングに似たものはあったが、 それは真のセグメンテーションではない。メモリ保護の金物がなかったから だ。) 80386から、セグメンテーションとページングが備わった。OS/2は、 この2つの金物機能を利用するので、OS/2は80386以降を要求するのである。 (訳注:16bit OS/2は80286で動いた)

セグメンテーションの背景にある考えは実の所8086よりずっと古い;しかし金 物のコストの所為で、長年の間それを実現できたのはわずかな計算機だけであっ た。(ページングはもっと乱暴で単純なので、金物設計者からもっと優遇され てきた。) 80286での極めて重要な発明は、設計者がセグメンテーションの 金物をCPUのチップ上においたことである。これで安価で量産できた。

80386のアドレス変換を行うハードは、2段階の変換を行う点で、いささか普 通ではない。プログラム - 即ち機械コード - の中ではアドレスは一対の値 (セグメント番号、セグメント中のオフセット)で表現される。(多くの場 合、機械コードにはセグメント番号を明示的に含めない。デフォルトとして 「現行のセグメント」を利用できるからだ。しかしプログラマはどのセグメ ントを操作対象にしているのか、常に認識していなければいけない。) セ グメンテーションのハードはこのようなアドレスを所謂「リニア・アドレス」 に変換する。次に、ページングのハードがこのリニア・アドレスを一対の値 (ページ番号、ページ中のオフセット)に変換する。このハードには各ペー ジの物理アドレスを示す表があり、この表を参照して最終的に物理アドレス を生成する。命令フェッチの中で、あるいは読み込みアドレスとして主記憶 に渡されるのは、この物理アドレスである。

ちょっと見にはセグメンテーションの金物とページングの金物とは同じ動作を しているように見える。そうだとしたら、両方の金物を備えるのは無駄なこと である。1段階変換で十分同じことができるであろう。しかしながら、幾つか 重要な違いがある:

  1. セグメントの大きさは可変であるが、ページの大きさは金物により一定 である。セグメンテーションは保護に関わっているので、セグメント境 界は「自然な」所に置かれる。例えば2つのモジュールの境界である。 セグメントの大きさは何にせよプログラマが必要とする値にされる。ペー ジ境界は、一方、ソフトウェアの構造に依存しない。全てのページが同 一の大きさであることが、ページングの金物にとっては本質的に重要で ある。
  2. セグメンテーションの金物は単なるアドレス変換器ではない;正当性や特 権の検査も行っている。ページングの金物はある程度の基本的なアクセ ス権の検査を行うが、根本的には表を眺めてアドレス変換を行うだけで ある。
ここでのポイントは、ページングとセグメンテーションの金物が異なった目的 を持っている事である。典型的なOSでは、セグメントテーブルはソフトウェア の一部として管理され、メモリアロケーションの面倒を見る。ページテーブル はディスクスワップを行うソフトウェアに関係する。この2つの金物は互いに 独立であり、この独立性はソフトウェアのデザインに反映しうる;ディスクス ワップのソフトウェアはセグメンテーションのことを一切知らないでよいし、 メモリマッピングのソフトウェアはページングのことを何等考える必要がない。 この「関知するものの分離」はバグのないプログラムを書くために、極めて重 要である。

セグメンテーションの金物も、ページングの金物も参照用の表を主記憶に置い ている。これではいかにもオーヴァヘッドが大きいように思われる。もし、ア ドレス変換が毎度毎度余計なメモリ参照を引き起こすなら、まさにそのとおり だろう。実際にはどちらの金物も、(高速なメモリに)自前のキャッシュを持っ ているので、システムがまともに動く。

スワップファイル

マルチタスクOSの利点は、同時にいくつかのプログラムを実行させられること である。不利な点の一つはシステムに過負荷をかけがちなことである。特に、 実際に機械に載っている以上の主記憶を使いたくなることだ。

スワップはディスクファイルを主記憶の延長のように扱う技術である。これは 以下のように動作する。プログラムのメモリはいくつかの仮想ページと呼ばれ るものから構成される。ページングの金物が仮想ページを物理ページにマップ する。ページ表(ページングの為のアドレス変換表)の各項目には物理ページ 番号だけではなく、いくたりかのフラグが含まれる。そのフラグの一つが、 「物理ページが存在しない」ことを示す。

ソフトウェアが主記憶に物理ページが存在するメモリページだけを使用してい る限り、特別なことは何も起きない。しかし、もしページングの金物が「ペー ジがない」ことを検出すると、「ページフォールト page fault」割り込みが 発行される。割り込みルーチンがこの条件を処理することになる。

ページフォールトには少なくとも2つの原因がありうる。明らかな原因として、 プログラミングの誤りでソフトウェアが不正なアドレスを要求した場合がある。 もちろん、これに対してユーザができることは何もない。単にそのソフトウェア を捨てるしかない。もう少し明らかでない原因として、アドレスは正当だが、ス ワップのソフトウェアがまだ必要なページを主記憶にロードしていないこともあ る。この場合はプログラムは暫時停止され、ディスクからページが読み込まれる ると実行が再開される。

結局、これにより主記憶の実効的な大きさがスワップファイルと呼ばれる特殊 なファイルの大きさ分拡大されることになる。ページング及びスワップの面倒 を見るためのシステムソフトウェアが、主記憶とスワップファイルとの入れ替 えを必要に応じて行う。

OSによっては、スワップファイルの大きさは固定である。OS/2では、CONFIG.SYS にスワップファイルの大きさの初期値を入れるが、スワップファイルは必要に 応じ大きくなったり小さくなったりする。この柔軟性には、それなりの代価が かかる:スワップファイルが拡大する時に、余計なオーヴァヘッドが生ずるの で、システムが突然遅くなる。このオーヴァヘッドを避けるには、スワップファ イルの初期サイズをほとんど拡大が起きることのない位大きくすればよい。

リアルモードとプロテクトモード

80x86ファミリの初期のプロセッサ - 8086, 8088, 80186, 80188 - は本来の セグメンテーションハードウェアを持っていなかったし、プログラムを互いに 保護することもできなかった。それらはアドレスを(セグメント番号、セグメ ント中のオフセット)の形で利用していはしたが、「セグメント番号」は単な る基底アドレスに過ぎず、セグメント表(存在しなかった)への参照値ではな かった。実際には、ソフトウェアは物理アドレスを直接扱っていたのだ。

セグメンテーションと保護は80286になって導入された。しかし、設計者はそ こで互換性の問題にぶつかった:ほとんどの現存するソフトウェアは8086用 で、従って80286は現存する8086用のソフトウェアを実行できなければならな かった。そこで使われた解決法はCPUに2つの実行モードを持たせることであっ た。「リアルモード」では、CPUは8086のように動き、セグメンテーションの 金物は停止される。「プロテクトモード」(訳注:protected mode。一般に 流布した表現を採用した)では、新しい保護機能が動作する。

結局の所、80286用のソフトウェアは大して出なかった。DOS/Windows市場が 余りにも優勢だったので、ほとんどの人は80286を8086としてのみ使った。 先進的な機能はほとんど無駄になってしまった。

80386では新たなひねりが加えられた。「リアルモード」「プロテクトモード」 は存在するが、プロテクトモードで特殊なセグメント形式を定義することが可 能になった。それは8086のイミュレータとして働く。この機能のおかげでリア ルモードに戻さなくても、プロテクトモードのOSを走らせ同時にこれら過去の アプリケーションを全て動かすことができた。これこそOS/2がDOS/Windowsア プリケーションを走らす時に使っている「仮想86モード」である。

この機能があれば、最早リアルモードはほとんどいらない。CPUは依然として リアルモードで起動するが、OS/2の初期化ルーチンがほとんど即座にプロテク トモードに変更する。

偶にOS/2のDOSイミュレーション機能をもってしても動かないDOSアプリケーショ ン - 普通はゲーム - がある。こうなるとCPUをリアルモードにして「純粋の」 DOSを走らすしかない。OS/2は「ハイバネーション」機能をもっており、これが 可能である。事実上それは機械を再起動するに等しい。OS/2はもはや動作して いない(訳注:「専用DOS」のことだと思う)。

32ビットプログラムって何?

32ビットソフトウェアについては、大量の屑文章が出回っている。ほとんどの 人はそれが正確には何なのか知らないが、32ビットソフトウェアはなんだか16 ビットソフトウェアより優れているらしいという印象を持っている。これは膨 大な宣伝の影響もあるのだが。

その印象は誤解に基づいている。この章の後の方で説明するように、実際の所 32ビットソフトウェアは等価な16ビット版より低速でメモリをより多く消費す る。

オリジナルの8086では、ほとんどの内部レジスタは16ビット幅であった。CPU は32ビットのアドレスを使ったが、それは16ビットのセグメントと16ビットの オフセットとに分解された。セグメント基底はほとんどの命令で暗黙のうちに 決められたので、この32ビットアドレスを16ビットアドレスと呼ぶのが一般的 だった。(問題を面倒にしたのは、主記憶のアドレスがたった20ビット幅であっ たことだ(訳注:セグメント基底を16倍し、これにオフセットを加えてアドレ スを生成した。従って20ビット幅しかなかった。)。)

80386以降のモデルでは、多くの内部レジスタが32ビット幅に拡張された。アド レスは48ビット幅になった:16ビットのセグメント番号と32ビットのオフセッ トである。(ここでも多くの人々はこれを48ではなく32ビットアドレスと呼ん だ。) 加えて、これらの新しいCPUは幾つかの新しい命令とアドレッシング モードを持つようになった。

ここで、またしても上位互換性の問題が現れてくる。レジスタの大きさを変え ずに8086のソフトウェアを正しく実行するにはどうするか。これを解決するた めに、全てのコードセグメントに2つの特殊なフラグが用意された。そのフラ グはセグメントディスクリプタ(訳注:segment discriptor。セグメント記述 子。セグメントの属性を記述するもの)に保存される。(セグメントディスク リプタはセグメンテーションの金物がアドレス変換に用いる表の項目である。) フラグの一つはレジスタを32ビットで用いるか、低位16ビットだけ用いるかを 指定する。もう一つはアドレスのオフセットを16ビットでとるか32ビットでと るか指定する。これはセグメント毎に指定され、新旧両方のソフトウェアの混 在を可能にする。16ビットの手続きを32ビットコードセグメントから呼ぶこと も、その反対もできる。

(実際、特殊な「エスケープ」コードすら存在し、16ビットセグメントの中に 隔離された32ビット命令を入れたり、逆をしたりできる)

本当に32ビットデータレジスタが必要だろうか? 私の経験(何年にも亙り、 たくさんのプログラムを書いてきた)からすると、16ビットでほとんど常に 十分だ。32ビット変数を必要とする場面は少しあるが、そんなにしばしばあ るわけではない。

一方、16ビットレジスタを使うと、プログラマは桁あふれの危険性を意識し なければいけないし、プログラムをそれなりにデザインしなければいけない。 世の中には良いプログラマを遥かに上回る数の駄目なプログラマがおり、こ の問題を考慮しないプログラムは数多い。実力のないプログラマにとっては、 32ビットデータレジスタへの移行は誤りの蓋然性を減らすことになるし、そ れは多分良い事であろう。

アドレスに関しては、事態は若干複雑である。16ビットのオフセットでは、 64キロバイトのセグメントが最大である。これは大量のメモリとは言えない。 もっと大きなセグメントを必要とする場面がある。

  1. アプリケーションによっては、大きな配列を - あるいは他の大きなデー タ構造を - 必要とする。こういった配列を複数のセグメントに分ける のは合理的とは言えない。明らかに32ビットオフセットが必要な一つの 例である。
  2. プログラマによっては、いまだにソフトウェアをモジュール化しないで 巨大な、一枚岩の(訳注:monolithic、モノリシック、一枚のシリコン ウェハの上に全回路が載った)ソースで書く人がある。その結果、大き なセグメントが必要になる。こんなのが言訳になるとは思えないが、需 要があることは否定できない。
  3. コンパイラによっては、セグメンテーションを有効利用するほど頭の良 くないのがある。全てのモジュールを一つのセグメントに押し込もうと するのだ。この手のコンパイラを書く人と話合わないと、またしても巨 大なセグメントが出現する。
  4. 多くのプログラマの間に、「フラットメモリモデル」にたいする強い欲 求がある。「フラットメモリモデル」が何かは後の章で説明する。この モデルは、巨大なセグメントをもたらす。(訳注:8086のセグメントに 泣かされてきたプログラマが多いのです。64Kまでの配列しか効果的に 舐められないんだもん)
理想的には、効率を上げるため可能な限り16ビットコードセグメントを使い たい。32ビットコードは、必要であるか、改良されたアドレッシングモード がもっと効率的なコードをもたらす場合以外は使いたくない。残念ながら、 これらを混在できるコンパイラはほとんどない。どちらか一方を選ぶしかな い。

よろしい、これで32ビットソフトウェアのなんたるかをある程度説明するこ とにはなるが、何故こんなに多くの人々が、16ビットアプリケーションから 32ビット版へ「グレードアップ」したがるのかは説明できない。何が魅力な のだろうか?

それは歴史的な偶然による。80x86での32ビットサポートは、OSがCPUのプロ テクトモードを活かしはじめた頃にほぼ一致して出現した。プロテクトモー ドへの移行は前進であった。多くのPCユーザが「一般保護違反」に悩んでい たし、一つアプリケーションがいかれても、システム全体を道連れにしてし まうという状況から逃れたかった。プロテクトモードOSは、救いであった。 「プロテクトモード」と「32ビットソフトウェア」の違いについてソフトウェ ア販売店は良く知らず、馬鹿げた宣伝のお陰でほとんどのユーザがそれらを 混同してしまった。 (訳注:16ビットで80x86の保護機構を活かしたOSはいくつかある。OS/2 1.x がそうだったし、BTRONの80286版(1B)もそうである。MINIXもそうだったか も。)

フラットメモリモデル

セグメンテーションが導入された時は、重要な進歩だとみられていた。これに よって、「クリーンな」プログラミング手法をサポートする確かな金物が得ら れたのだ。例えば、プログラムの実行部分とデータ部分とをきれいに分離する などである。このアイデアが守られたら、現在私達はもっと信頼性の高いソフ トウェアを手にしているだろう。

残念ながら、セグメンテーションは高くついた。それは洗練されたアドレス変 換を高速で(容認できないほどのオーヴァヘッドをもたらさないように)行え る金物を必要とした。当時の技術でもこれは可能だったが、計算機の総コスト を引き上げる事になった。恐らく金物設計者はコストの上積みは何があっても 避けなければならないと決めたのだろう;実際の製品は極わずかしか出なかっ た。

80286が出現した時、技術がついに追いついた;漸く、何年もそこにあったア イデアを、容認できる程度のコストで実現したのだ。

何とも哀れな事に、セグメンテーションの機能を利用した者は、ほとんどいな かった。いくつか理由はあった。

言語に関係した問題もあった。それについては後で述べよう。しかし、まずは 「リニアアドレッシング」とは何かを見る事にする。

アドレス空間は、アドレスに線形演算が適用可能なら、リニア(線形)である。 例えば、ポインタp1とp2について、p1+p2もp1-p2も意味のあるアドレスでなけ ればならない。

セグメント化されたアドレスは、定義上線形ではない。セグメント化メモリで はp1+p2には意味がないし、p1-p2はp1とp2とが共に同じセグメントのポインタ である場合に限り意味を持つ。セグメント化アドレス空間は、ある種のアドレ ス演算を厳しく制約する。

強く型付けられた(訳注:データの型を厳密に扱う、ということ)言語では、 このような制限は意味のあるものである。実際、セグメント化アドレス空間は モジュール性の概念に力をいれている、より近代的なプログラミング言語(Ada, Modula-2, Oberonなど)には最適である。モジュールとセグメントの間には、 極めて自然な対応関係をつけられる。

ところが、現在のOSは、より旧式の言語であるCがほぼ全盛だった頃デザインさ れた。Cはセグメント化メモリモデルとはあまり相性がよくない。Cは セグメンテーションの金物が違反としてトラップをかけかねない操作を許してい る(実行コードへのポインタとデータへのポインタの混用、ポインタへの無制限 な線形演算など)。セグメンテーションが防ごうとするものは、センスのあるプ ログラマなら不適当だとして避けるようなものだ、ということに、同意してくれ ると思う。コンパイラは言語の標準が許すものなら、なんでも許してしまう。ど んなに馬鹿げたことでも。そうでなければ、標準に合致しないコンパイラなのだ。

結果として、Cプログラマは一般にリニアアドレス空間を好む。またこの伝統は、 C++プログラマにも引き継がれているようだ。これはOS/2に大きな影響を与えた。 なんとなればOS/2のプログラムのうちCやC++で書かれたものがあまりに多いから だ。(訳注:日本に至っては、Algol系プログラマは絶滅寸前ではないだろうか。)

80x86でリニアアドレス空間を使えるのであろうか。そう、セグメンテーション は止められない。しかしそれがないように見せかける方法がある。それは、プロ グラム全体(実行コードもデータもひっくるめて)を一つの巨大なセグメントに 押し込み、セグメントレジスタを全て同じセグメントを指すように設定する、と いうトリックである。見方を替えれば、複数のセグメントを使ってはいるが、そ れらがぴったり重なっていて、同一の物理メモリにあるようにするのである。こ れが80x86(より正確には80386以降)での「フラットメモリ」に他ならない。

以上の議論から判ると思うが、私はフラットメモリモデルが好きではない。実際、 私はセグメンテーションの利点を投げ捨ててしまうのは、狂気の沙汰だと思って いる。私がこんなことを言えるのも、OS/2のソフトウェアを販売していないから だ。ソフトウェア屋だったら、こんな贅沢は言えない;客を「気違い」なんて言 おうものなら、商売あがったりになるのが落ちだ。フラットメモリモデルこそ、 ほとんどのOS/2プログラマのお望みのもので、人は望んだものしか得られない。 (訳注:実行コードを実行中に書替えるという技法があるが、同時に、おかしな ポインタ操作によって、コードを壊してしまうこともある。コードセグメントと データセグメントとをハードウェアレベルで区別すれば、コードをプログラム自 体が破壊することを検出/予防できる。このような利点を著者は考えているのだ と思う。)


[ 第一部 | 第二部 | 第三部 ]
オリジナル: 7 April, 1997 日本訳更新: 15 April, 1997