🎓 レベル:基礎 | 重要度:A(必須)
📎 前提:OSの役割とカーネル | 関連:仮想記憶とページング・メモリ階層とキャッシュ
要点(BLUF)
- プログラムが使うアドレス(論理/仮想アドレス)は、実際のDRAM上の場所(物理アドレス)と別物。両者を MMU(メモリ管理ユニット) がアクセスのたびに変換する。
- この間接層のおかげで、各プロセスは「アドレス0から始まる連続した自分専用メモリ」を持っているように見える(実際は物理メモリ上にバラバラに散らばっていてよい)。
- 利点は3つ:保護(他プロセスのメモリに触れない)、再配置(物理のどこに置いてもよい)、仮想化(物理より大きく見せる)。
概念 ── 2種類のアドレス
コンパイルされたプログラムには「変数xは番地0x1000」のようにアドレスが埋め込まれます。でも、複数のプロセスが同時に走るのに、全員が0x1000を物理メモリの同じ場所に書いたら衝突します。
解決は アドレスを2層に分けること。
- 論理アドレス(仮想アドレス):プロセスやCPUの命令が扱うアドレス。各プロセスは0から始まる自分だけの空間を持つ。
- 物理アドレス:実際のDRAMのどのセルか。OSとハードだけが扱う。
CPUが論理アドレスでメモリにアクセスするたび、MMUというハードがそれを物理アドレスへ翻訳します。
flowchart LR
CPU["CPU(論理アドレスを発行)"] --> MMU["MMU(変換)"]
MMU --> MEM["物理メモリ(DRAM)"]
OS["OS(変換表を設定)"] -.->|"プロセス切替で表を差し替え"| MMU
要するに、プロセスは「自分用の地図(論理)」で動き、MMUが「実際の住所(物理)」へその場で読み替える。プロセスを切り替えると(プロセスとスレッド)OSが変換表を差し替えるので、同じ論理アドレス0x1000でも別プロセスでは別の物理場所を指します。
仕組み ── 最も単純な変換(ベースとリミット)
歴史的に最も単純な方式がベースレジスタ+リミットレジスタです。
- ベース:そのプロセスの物理開始アドレス。
物理 = 論理 + ベース。 - リミット:許される最大論理アドレス。これを超えるアクセスはハードが例外を上げOSが介入(保護)。
flowchart LR
la["論理アドレス"] --> chk{"リミット以下?"}
chk -->|"No"| trap["例外 → OSが介入(不正アクセス)"]
chk -->|"Yes"| add["+ ベースレジスタ"]
add --> pa["物理アドレス"]
これで、プロセスを物理メモリのどこに置いてもベースを変えるだけで動き(再配置)、リミットで他人の領域へのはみ出しをハードが強制的に防ぐ(保護)。ただしこの方式は1プロセス=連続した1ブロックを要求するため断片化に弱く、現代はページング(仮想記憶とページング)に置き換わりました。考え方の出発点として重要です。
具体例 ── なぜ「自分専用に見える」か
2つのプロセスが同じプログラム(同じ実行ファイル)から起動されると、両方とも論理アドレス上は同じレイアウト(同じ番地にmain関数、同じ番地に大域変数)になります。しかしMMUの変換表が別なので、物理メモリ上では完全に別の場所に展開され、互いに干渉しません。これが「同じプログラムの複数起動」が衝突しない理由です。
仕組みの直観 ── なぜこの間接層を挟むのか
「論理→物理」という余分な変換は一見ムダですが、間接層には絶大な利点があります(計算機科学の万能薬「もう1段の間接参照」)。
- 保護:変換表にない物理メモリへはそもそもアクセスできない。バグや悪意を物理的に封じる。
- 再配置の自由:プログラムは「自分は0番地から」と思い込んで作れる。実際にどこに置くかはOSが後から決められる。リンク(リンクとロード(実行ファイルがプロセスになるまで))が楽になる。
- 仮想化:物理にないページを「ディスク上」に追い出し、必要時に持ってくる。これで物理より大きなメモリを見せられる(仮想記憶とページング)。
- 共有:別プロセスの論理ページを同じ物理ページに向ければ、共有メモリ(プロセス間通信(IPC))やライブラリの共有が実現する。
⚠️ よくある誤解・落とし穴
- 「ポインタの値=物理アドレス」→ ほぼ常に論理(仮想)アドレス。物理を直接見るのはカーネルの一部だけ。
- 「変換はソフトが毎回行う」→ 通常はMMU(ハード)が高速に行う。OSは表を用意するだけ。
- 「アドレス空間は物理メモリのサイズ」→ 論理空間は物理より大きくできる(仮想記憶)。逆に物理が少なくても広い論理空間を見せられる。
- 「ベース+リミットが今の主流」→ 現代はページング。ベース+リミットは概念理解のための原型。
対応ラボ
なし(変換の数値は 仮想記憶とページング の 03-02_address_translation.py で実証)。
関連
- 実用の変換方式は 仮想記憶とページング
- 「遅い層を速い層で隠す」発想の原型は メモリ階層とキャッシュ
- 保護の上位の話は セグメンテーションとメモリ保護