Top > OS > MMU


リニューアル

サイトリニューアル中です。本ページは以下URLへ移動しました。
Prog.さな雑記

MMU (前説)

マルチタスクとメモリアドレス

複数のプログラムが同時に動く(動いているように見える)仕組みは ここのようなものだが、実行するプログラムは マルチタスクの場合でも、当然メモリ上に存在している。 メモリは、0 番地から始まり、その CPU に物理的に接続できる最大メモリ量までの アドレスが割り振られている。 これはメモリアドレスを指定するピンの数で決まり、

  • 20 本なら 1M バイト
  • 24 本なら 16M バイト
  • 32 本なら 4G バイト

というように計算できる。

物理メモリアドレスが 64K バイト(アドレス線の数は 16 本)の CPU を 例として考える。メモリアドレスは 0000H 番地から FFFFH 番地までである。 複数のプログラムをメモリ中に共存させるため、

  • プログラムA は 0100H 番地から
  • プログラムB は 1100H 番地から

という具合にプログラムが重ならないよう、 他のアドレスに読み込んでいけばいいようにも思う。

プログラムの配置
プログラムの配置.jpg

この方法には

  • プログラムそのものに埋め込まれているアドレスをどうするのか
  • メモリが虫食いになる

という問題がある。

プログラムそのものに埋め込まれているアドレスをどうするのか

例えば、次のようなプログラムを想定する。

mov [110], ax

この 110 は 110H 番地を表している。 もしプログラムの中にこの命令が出てくると、プログラムA の領域に 値を書き込んでしまうことになり、プログラムA の動作は破綻してしまう。 この問題は、下記の方法で解決することが可能である。

相対アドレッシング
プログラムを作成する時にメモリアドレスを使うのではなく、 現在のアドレスからの距離(オフセット) を利用しなければならない、 と取り決めておく方法である。 例えば、100H 番地にある命令が 110H 番地にデータを書き込みたいのなら、 「今の番地より 10H 番地先」というアドレスの指定方法を使う。 こうすれば、仮にこの命令が 1100H 番地に読み込まれたとしても、 書き込む先のアドレスは1110H になり、問題は起こらない。
(メモリアドレスを直に指定する方法を絶対アドレッシングという)

メモリが虫食いになる

例えば、プログラムA の実行が終わり、不要になったとする。 すると、メモリ中のプログラムA が占有していた領域は、 未使用の空き状態になる。その後、新たにプログラムC がプログラムA のサイズと 全く同じか小さいなら、プログラムC をプログラムA が占有していた領域に 読み込めばいいだけだが、異なるプログラムが全く同じサイズになることは、 ほとんどあり得ない。 従って、プログラムC は他のメモリ領域に読み込まねばならず、 かつてプログラムA が占有していた領域は空いたままとなる。

複数のプログラムを読み込んだり終了させる動作を繰り返していくと、 この例のようなメモリ内の虫食い穴が増えていき、 実際に利用できるメモリの量がどんどん減少していく可能性がある。 ちなみに、この虫食い問題に関しては、OS がプログラムの実行の隙を見て、 プログラムを移動させて解決する方法が存在する。

例えば、先の例ならプログラムA の実行が終わった時点で、プログラムB が 忙しくない(キーボード等からの応答待ち等)のなら、 プログラムA が占めていた部分までプログラムB を移動させてしまうの方法である。 このような処理をガベージコレクション(ごみ掃除)といい、 実際にガベージコレクションによってメモリの虫食いを防ぐマルチタスクOS は いくつか存在する。ただ、ガベージコレクションの動作は無駄に等しいため、 その分だけパフォーマンスを犠牲にする難点があると言える。

MMU (本編)

マルチタスクを実現する上で、メモリアドレスは厄介な問題である。 そこで登場したのが「メモリマネージメントユニット(MMU)」という機構である。 MMU はなかなか理解が困難とされているが、現在の OS を語る上では 欠かせないものである。

シンプルな MMU の例

非常にシンプルなMMU の例として、64K バイトのメモリが接続できる CPU を 用いて説明する。CPU には 16 本のアドレス線(アドレスバスという)があり、 メモリに接続されている。

イメージ
メモリバス16本.jpg

上位 4 本のアドレスバスに 16 バイトのメモリを接続し、 そのメモリの 8 ビットのデータ出力をメモリに繋いでみる。

イメージ
シンプルMMU.jpg

上位4 ビットの線を接続するため、その線だけで指定できるアドレスは 0H~FH までの16 バイトである。 また、16 バイトのメモリの出力をアドレスの代わりとして使う。 こうすることで、メモリアドレスは下位12 ビットと合わせて20 ビットのメモリアドレスに拡張される。16 ビットのメモリアドレスのままなら 64K バイトしか 使用できないところ、この方法なら 1M バイトのメモリまで接続できることになる。 プログラムから見たメモリアドレスは

シンプルMMU見た目.jpg

となる。 CPU 自体は 16 ビットのアドレスしか使えないため、 プログラム上では変わらず16 ビットのアドレスを用いることになる。

プログラムから見たアドレス

例えば、プログラムで「10F0H」というアドレスを指定したとする。 この時、上位 4 ビットの「1」は、アドレスバスの上位4 ビットに接続された 16 バイトのメモリを指し示すアドレス「1」となる。 仮に「1」のアドレスに 55H が入っていたとすれば、 10F0H というメモリアドレスは、550F0H というアドレスに変換され、 実際のアドレス(物理メモリ)のアドレスを指定することになる。

まとめ

  • プログラムから見たアドレスを「論理アドレス」と呼ぶ
  • 実際のメモリ上のアドレスを「物理アドレス」と呼ぶ
  • 16 バイトのメモリを「ページテーブル」と呼ぶ
  • このような仕組み全体をMMU と呼ぶ

メモリ問題解決?

プログラムから見える論理アドレスは、物理メモリ上の任意のアドレスにある 4K バイトが割り当てられ、その割り当てはページテーブルによって設定できる。 この仕組みをマルチタスク OS に応用すると、先のメモリ問題は全て解決する。 プログラム毎に、ページテーブルを書き換えてやればよい。 プログラムA 用のページテーブル、プログラムB 用のページテーブル・・・ という具合にあらかじめ物理メモリの中から空いている4K バイトの空間(メモリペー ジ) を割り当てる。 プログラム上で扱えるのは論理アドレスだけなので、

  • プログラムA がプログラムB に進出して書き換えることは不可能
  • プログラムA からはプログラムB のメモリは全く見えない

となる。また、虫食いも起きない。 プログラムA の実行が終わったら、不要になった空間(メモリページ)を使って 別のプログラムの論理アドレス空間を作れば良いからである。

全体像
シンプルMMU全体像.jpg

実際のMMU

上記で説明した MMU の仕組みは、最もベーシックなものである。

例えば、現在のパソコンのCPUは 32 ビット=4G バイトの論理アドレス空間があり、 物理アドレス空間は 36 ビット= 64G バイトである(サーバ用ではさらに大きな物理アドレス、論理アドレスが扱えるCPU も登場している)。 このような非常に大きなメモリが扱える CPU で、先のシンプルな MMU を 利用しようとすると、ページテーブルが大きくなりすぎる

例えば、32 ビットの論理アドレスで、メモリページが 4K バイトとすると、 1 つのプロセスに対して 3M バイトものページテーブルが必要になり、 ページテーブルの容量だけでも馬鹿にならない。 そこで、論理アドレスを 3 つに分け、2 つのページテーブルを併用する などの方法が用いられている。

MMU の仕様は CPU のアーキテクチャによって多少異なるが、 どのようなCPU のMMU であっても、基本は前節のような仕組みが用いられている。 そして、ほとんどのマルチタスクOS では MMU を使用してプログラムごとに 異なる論理アドレス空間を与え、メモリ問題を解決している。


添付ファイル: fileメモリバス16本.jpg 796件 [詳細] fileプログラムの配置.jpg 706件 [詳細] fileシンプルMMU見た目.jpg 732件 [詳細] fileシンプルMMU全体像.jpg 504件 [詳細] fileシンプルMMU.jpg 480件 [詳細]

リロード   凍結解除 コピー 名前変更   ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS
Last-modified: Wed, 28 Oct 2020 14:05:47 UTC (399d)