OS

【図解】いまさら人には聞けないMMUの仕組み

2020年10月17日

MMUとは?

MMUの正式名称は、「Memory Management Unit」といい、「メモリ管理ユニット」と訳します。

物理アドレスと論理アドレスを相互に変換できるようにする仕組みで、
主にOS(Operating System)が責務を担う機能です。

Windowsを始め、Linux、FreeBSDなど、最近のOSには必ずと言っていいほど
MMUの機能が備わっています。

SANACHAN
SANACHAN
論理アドレスは、仮想アドレスとも言われ「VM (Virtual Memory)」と表されたりします。

 

物理アドレス

物理アドレスとは、メモリのハードウェア上の番地です。

物理的なモノ(メモリ)のアドレスを指すため、物理アドレスと言います。

 

論理アドレス/仮想アドレス

実際に物理的なモノとして存在しないアドレスで、
プログラム上でのみ意味を持つ架空のアドレスのことです。

 

なぜMMUがOSに必要なのか

マルチプロセス、またはマルチタスクという言葉を聞いたことはないでしょうか。

実は、複数のプログラムが同時に動く仕組みであるマルチプロセス・マルチタスクを実現するためにMMUが必要になります。

例えば、プログラムAプログラムBが同時に実行されている(マルチプロセス)場合を考えましょう。
同時に実行する場合、メモリ上に次のようなものが記憶されている必要があります。

  • プログラムAのバイナリ (プログラム自体)
  • プログラムAが使用するスタック (オート変数とか関数呼出スタックの保存、等)
  • プログラムAが使用する一時的な保存領域 (ファイルの中身を読込むバッファ、等)
  • プログラムBのバイナリ
  • プログラムBが使用するスタック
  • プログラムBが使用する一時的な保存領域

 

MMUが無い場合どうなる?

簡単にするため、メモリが64Kバイトの場合で考えてみましょう。
物理アドレスは 0000H 番地から FFFFH 番地になります。

SANACHAN
SANACHAN
番地最後の「H」は、Hex (16進数) であることを示しています。

 

先ほどのプログラムAとプログラムBを同時に実行する場合、メモリ上に同時に存在している必要があります。

  • プログラムAは、0100H 番地から配置する
  • プログラムBは、1100H 番地から配置する

という具合に、それぞれのプログラムが重ならないように配置すれば、問題ないようにも見えます。

プログラムの配置

プログラムAとプログラムBの配置

 

しかし、この方法には以下のような問題が生じます。

問題点

  • プログラムそのものに埋め込まれているアドレスはどう扱うのか
  • プログラムの起動/終了を繰り返しているうちに虫食いになる

 

問題点:プログラムそのものに埋め込まれているアドレスの扱い

例えば、以下のような命令がプログラムBに組み込まれている場合を想定します。

この命令の 110 は 110H 番地を表しており、ax という汎用レジスタから 110H 番地に値を保存するという動作をします。もし、この命令が実行されると、プログラムBがプログラムAの領域に値を書き込んでしまうことになり、プログラムAの動作が破綻します。

SANACHAN
SANACHAN
この問題自体は、「相対アドレッシング」という方法で回避することは可能です。
相対アドレッシングって何ですか?
MAI
MAI
SANACHAN
SANACHAN
アドレスを使うのではなく、 現在のアドレスからの距離(オフセット) を利用する、 と取り決めておく方法ですね。 例えば、100H 番地の命令で 110H 番地にデータを書込む場合、「今より 10H 番地先」という指定方法を使う。こうすれば、仮にこの命令が 1100H 番地で実行されたとしても、書込む先は 1110H になるので問題が起こらなくなります。
なるほど~!じゃあこの問題は解決するんじゃないの?
MAI
MAI
SANACHAN
SANACHAN
メモリアクセスする度にアドレスを演算するため、処理速度(性能)が極端に悪くなります。

 

問題点:プログラムの起動/終了を繰り返しているうちに虫食いになる

例えば、以下のような流れを考えてみましょう。

簡単な流れ

  • プログラムAの実行が終了し、使用していたメモリが不要になった
  • プログラムAが占有していた領域が、未使用の空き状態になる
  • 新たにプログラムCを実行する

 

新たに実行するプログラムCがプログラムAのサイズと 全く同じか小さいなら、プログラムAが占有していた領域に読み込めばいいだけだで問題ないように思えます。

しかし、異なるプログラムが全く同じサイズになることは有り得ません。そのため、プログラムCは他のメモリ領域に読込まねばならず、かつてプログラムAが占有していた領域は空いたままとなります。

プログラムの配置2

プログラムBとプログラムCの配置

複数のプログラムを読込んだり終了させる動作を繰り返していくと、このようなメモリ内の虫食い穴が増えていき、実際に利用できるメモリの量がどんどん減少していく可能性があります。

 

そこで登場したのがMMUの仕組み

仕組みの概要

先ずは、簡単な仕組みから見ていきましょう。

アドレス変換概要

MMUは先の問題を解決するため、論理アドレスの考え方を取り入れて、物理アドレスと論理アドレスを相互にアドレス変換を行います。アドレス変換を行うための表をページテーブルと言い、TLB (Translation Lookaside Buffer) というバッファに保存して参照します。

 

仕組みの詳細

アドレス変換詳細

先ほどと同様に、メモリが64Kバイトの場合で考えてみましょう。64Kバイトのアドレスは 16bit (2^16乗 = 64K) で表現され、それぞれのビットを信号で伝えるアドレスバスがメモリに接続されます。

アドレス変換の流れ

  • 例えば、論理アドレス 1100H 番地を上位8bit (ページ番号)と下位8bit (オフセット) に分離
  • 論理ページ番号 11H と一致する物理ページアドレスの上位8bitを、TLBを参照して変換
  • 下位8bitは変換せずにそのまま使用
  • すると、論理アドレス 1100H 番地を物理アドレス 3300H 番地に変換可能

 

SANACHAN
SANACHAN
ハードウェアやシステムによって、bit数は変わります。

ポイント

MMUとは、TBLを使ってページ変換テーブルを保持し、物理アドレスと論理アドレスを相互に変換する仕組みです。

 

MMUを搭載するメリット

MMUを使うと、先のメモリに関する問題を解決できるだけでなく、他のもメリットがあります。

 

扱えるメモリ容量が増える

アドレス変換応用概要

例えば、先ほどのメモリが64Kバイトの場合、つまりCPUが持っているアドレスバスが16本の場合を考えましょう。

上位4本のアドレスバスに16バイトのメモリを接続し、そのメモリの8本のアドレスバスをメモリに繋いでみます。

上位4bitの線を接続するため、その線だけで指定できるアドレスは 0H~FH 番地までの16バイトですね。また、16 バイトのメモリの出力をアドレスの代わりとして使うイメージです。

こうすることで、CPUが扱えるメモリアドレスは下位12bitと合わせて20bitのメモリアドレスに拡張することができます。

つまり、16bitのメモリアドレスのままなら 64Kバイトしか扱えないところ、この方法なら 1Mバイトのメモリまで扱うことができるようになります

 

メモリ破壊を抑止できる (メモリバリア)

アドレス変換を行うことで、メモリ破壊を抑止することができます。

例えば、プログラムAがアクセスする論理アドレス 0100H 番地と、プログラムBがアクセスする論理アドレス 0100H 番地は、実際には異なる物理アドレスを指します。言い換えると、プログラムAがアクセスする物理アドレスは、プログラムBには分かりませんし、OSを除くその他すべてのプログラムで知る術がありません。

プログラムAが暴走して変な論理アドレスにアクセスしても、アドレス変換エラーが発生したり変な物理アドレスに変換されるため、他のプログラムが使用しているメモリ領域に危害を加えることが無くなるということです。また、変換後の物理アドレスへのアクセス権をOSから与えられていなければ、暴走したプログラムをOSが強制終了させることもできます。

SANACHAN
SANACHAN
この事象が発生した場合、Linux系では「SIGSEGV」や「SIGBUS」によってプログラムが強制終了します。

 

こちらの記事もよく読まれています

  • この記事を書いた人
  • 最新記事
SANACHAN

SANACHAN

「生涯一エンジニア」を掲げ、大手グローバル企業でSE/PGとして8年勤め、キャリアアップ転職した現役のエンジニアです。世にあるメジャーな全プログラム言語(コボル除く)を自由に扱えます。一児の父。自分のため、家族のため、日々勉強してます。システムエンジニア、プログラミングに関する情報を蓄積している雑記帳です。

-OS
-, ,