仮想メモリ入門:仕組み・主要用語からページ置換・性能チューニングまで徹底解説

導入 — 仮想メモリとは何か

仮想メモリ(virtual memory)は、実行中のプログラムに「連続した大きなアドレス空間」を提供し、物理メモリ(RAM)の制約を抽象化・緩和するためのOSとハードウェアの仕組みです。アプリケーションは仮想アドレスを用いてメモリにアクセスし、実際の物理アドレスへの対応(アドレス変換)はメモリ管理ユニット(MMU)とOSが協調して行います。これにより、プロセスごとのメモリ保護、効率的なメモリ共有、需要に応じた読み込み(デマンド・ページング)、スワップアウト/インなどが可能になります。

仮想メモリが必要とされる理由

  • プロセス分離と保護:各プロセスに独立したアドレス空間を与えることで、誤動作や悪意あるコードが他プロセスやカーネル領域を直接破壊するのを防ぐ。
  • 論理的な大容量メモリ:物理メモリより大きなアドレス空間を提供でき、必要に応じてディスクを利用してメモリ不足を回避できる。
  • 効率的な共有:共有ライブラリやメモリマップドファイルを複数プロセスで同じ物理ページを指すように設定し、メモリ利用の効率化を図る。
  • 柔軟な割当:起動時にすべてのメモリを確保せず、実際に参照されたページだけを読み込むデマンド・ページングで高速化と資源節約を実現。

基本構成要素と用語

以下は仮想メモリの理解に必要な主要な要素です。

  • 仮想アドレス(VA)/物理アドレス(PA):プログラムが使用するアドレスと、実際のRAM上のアドレス。
  • ページ(page):仮想→物理の変換単位。一般にサイズは4KiBが標準で、2MiBや1GiBの大きいページ(HugePages)も利用される。
  • ページテーブル:仮想ページごとに対応する物理フレーム番号や属性(読み書き可否、ユーザ/カーネルなど)を保持するデータ構造。
  • TLB(Translation Lookaside Buffer):最近使われた仮想→物理変換をキャッシュする高速メモリ。TLBミスが発生するとページテーブル参照が必要になる。
  • ページフォールト(page fault):アクセスした仮想ページが現在物理メモリに割り当てられていない場合に発生する例外。OSがハンドリングし、ページのロードや保護違反処理を行う。
  • スワップ(swap)/ページアウト:物理メモリが不足したとき、未使用のページをディスク上のスワップ領域に書き出すこと。

アドレス変換の流れ(概略)

CPUが仮想アドレスでメモリアクセスを行うと、MMUはTLBをまず参照します。TLBに変換情報がなければページテーブルを参照して物理アドレスを得ます。対応する物理フレームが割り当てられていなければページフォールトが発生し、OSが対応ページをディスクからメモリへ読み込み(あるいは新しいページを割り当て)てページテーブルを更新します。その後、アクセスは再実行されます。

ページサイズと多段階ページテーブル

ページサイズは性能とメモリ効率のトレードオフです。小さいページは内部断片化を減らすがページテーブルが大きくなりやすい。大きいページはTLB効率や連続転送の観点で有利です。現代の64ビットシステムでは階層化されたページテーブル(例えばx86-64の4段階、5段階も対応可能)を採用し、必要な部分だけをメモリ上に確保してメモリ使用量を抑えます。また、インバーテッドページテーブルやハッシュベースの手法を使うOSもあります。

ページ置換アルゴリズムとスラッシング

物理メモリが満杯になると、OSはどのページを退避(スワップ)するかを決める必要があります。代表的アルゴリズム:

  • FIFO(先入れ先出し)
  • LRU(最も参照されていないものを選ぶ)や近似LRU(参照ビットを用いるなど)
  • Clock(時計アルゴリズム) — LRUの近似で広く使われる
  • 最適アルゴリズム(理論上最適だが実用では未知の未来アクセスが必要)

スラッシング(thrashing)は、頻繁にページフォールトとスワップが発生してCPU時間がメモリ管理に取られ、実効的な進捗が落ちる状態です。対策にはワーキングセットサイズの管理、スワップ領域の増加、ページサイズの調整などがあります。

デマンド・ページングと事前読み込み(プリフェッチ)

デマンド・ページングは、ページが参照された時点で初めて読み込む方式でメモリの無駄を減らします。一方、OSやハードウェアは局所性を利用して連続ページを事前に読み込む(プリフェッチ)こともあります。I/O負荷やアクセスパターンによって、どちらが有効かが変わります。

共有、コピーオンライト、メモリマップドファイル

仮想メモリにより、複数プロセスで同一の物理ページを読み取り専用で共有することが可能です。fork() によるプロセス複製ではコピーオンライト(COW)が用いられ、親子が同じ物理ページを共有し、どちらかが書き込む時点で初めてコピーされます。これによりforkのコストを大幅に削減できます。

また、ファイルを仮想アドレス空間にマップ(mmap 等)すると、ファイルの内容がページ単位で必要に応じてメモリにマッピングされ、ファイルI/Oとメモリ管理が統合されて効率的になります。

ハードウェアとOSの協調(MMU、TLB、ASLR など)

MMUは仮想→物理変換を実際に行うハードウェアで、TLBはその変換を高速化します。現代のCPUはTLBを複数レベル持ち、TLBミスハンドリング(ハードウェアでのページテーブルウォークやOS介入)を最適化しています。

セキュリティ上の重要な機能としてASLR(Address Space Layout Randomization)があり、仮想アドレス空間内の領域配置をランダム化してバッファオーバーフロー等の攻撃を困難にします。これは仮想メモリがあるから実現できる防御策です。

現代OSにおける実装例とチューニング項目

Linux、Windows、macOS いずれも仮想メモリを中心に設計されています。実装の違いとしてはページ置換のポリシー、スワップ挙動、巨大ページ(HugeTLB)のサポート、メモリ過剰割当て(overcommit)設定などがあります。開発者や運用者がチェックすべき主要項目:

  • スワップの有無やサイズ、スワップが発生する閾値(swappiness等)
  • HugePages(大ページ)を利用するかどうか — TLBミス削減やI/O効率向上に効果がある
  • mlock()/mlockall() によるページ固定(リアルタイムアプリやデータベースで重要。ただし物理メモリを占有する)
  • メモリマッピング(mmap)やファイルI/Oのパターン最適化
  • ASLRやセキュリティ設定の検討

パフォーマンス面の注意点

仮想メモリは利便性を高めますが、性能ペナルティも存在します。TLBミスやページフォールトはコストが高く、スワップアウト/インはディスクI/Oを伴うため遅いです。キャッシュ性の高いアクセスパターン(局所性)を保つ、メモリ使用量を過度に増やさない、必要ならメモリ固定や大ページを使うなどの対策が必要です。

まとめ

仮想メモリは、プログラムに対して使いやすく安全な大きなアドレス空間を提供する重要な基盤技術です。MMU、TLB、ページテーブル、ページフォールト、スワップ、ページ置換アルゴリズムなどの要素が協調して動作します。適切な理解とチューニングにより、性能と安全性の両立が可能です。特に大規模サービスやリアルタイム処理、データベースなどでは仮想メモリの振る舞いを理解して最適化することが重要になります。

参考文献