khurata’s blog

khurata’s blog

仮想記憶について―OS 概説・外論―

(もともと「Yahoo!知恵袋」の「知恵ノート」だったものを転載しています)
(最終更新日時:2015/10/10)投稿日:2012/8/25

はじめに

 現在、実用的な OS のほとんど全てに、「仮想記憶」(仮想メモリ)という技術が搭載されています。
 この仮想記憶という技術は、そもそもが「その存在を気にしなくても良い」ように作られている技術なのですが、コンピュータを使ったり、プログラミングをするにあたっては、時として、知っておく方が良い場合もあります。
 知恵ノート「OS とは何か?―OS 概説―」 https://khurata.hatenablog.com/entry/2019/04/04/053104 でも、仮想記憶については触れたのですが、文字数がギリギリだったため、説明が足りない所もありました。
 本ノートでは、より深く掘り下げて説明し直してみたいと思います。

 

なぜ必要なのか

 仮想記憶技術を短く説明すると、「実際に搭載されている主記憶(物理メモリ、実メモリ)と、補助記憶(磁気ディスク、SSD など)を組み合わせて、主記憶より大きなメモリアドレス空間を扱えるようにする技術」です。

 仮想記憶技術が生まれ成熟したのは、1970年代の事です。 その頃、実メモリは大変高価で、1台のコンピュータに実装出来るメモリ量はせいぜい 16M(メガ)といったところでした。
 しかし、複数のプログラムを同時実行し、巨大なデータを扱うには、16M では到底足りず、速度を犠牲にしてでも、広大なメモリ空間が必要とされたのです。

 それから 40年を経た現代、実メモリの価格は劇的に下がりましたが、それでもなお、実メモリのビットあたり単価は、補助記憶装置を大きく上回っています。
 2012年後半、2TB(テラ・バイト)の HDD は 1万円を切っていますが、2TB のメモリとなると、個人レベルではまだまだ夢物語です。

 つまり現代においても、「高価な実記憶と廉価な補助記憶」の構図は崩れておらず、広いメモリを使いたければ仮想記憶技術のお世話にならざるを得ません。

 

どういう技術なのか

 実際にコンピュータに搭載されているメモリ……これを物理メモリとか、実メモリ、あるいは主記憶 main memory などと呼びますが、その実メモリの範囲を超えたメモリ空間(仮想メモリ)を、擬似的に実現するのが仮想記憶技術です。

 仮想記憶は、現代の実用的な OS のほとんど全てでサポートされています。 つまり、OS 上で動作するプログラムは、全て、仮想メモリ空間で実行されているのです。
 たとえば 32ビット OS の場合、実メモリが 512MB(メガ・バイト)しか無い PC であっても、1つのアプリケーション・プロセスは 4GB(ギガ・バイト)、つまり 4096MB のメモリ空間を、プロセス毎に独立して持っています。
 もし同時に 10個のアプリケーションを起動していたら、その時 OS は合計 40GB のメモリ空間を扱っているのです。(実メモリは 512MB しか無いのに!)

 これら「プロセス毎のメモリ空間」は、仮想記憶技術によって「作り出された」仮想メモリ空間です。

 仮想メモリ空間は、主記憶と補助記憶(現在、そのほとんどは磁気ディスクないし SSD です)を組み合わせ、それらに仮想的なメモリアドレスを割り振る事で実現されます。

 もちろん、CPU が実行するプログラムは、必ず実メモリに無くてはなりません。
 しかし、CPU は、一時に一部の実メモリしか参照しないので、「その時『見てない』部分」を、律儀に実メモリに置きっぱなしにする必要もありません。 プログラムの実行に必要な「全てのメモリ空間」を、律儀に実メモリへ置きっぱなしにしなくても良いわけです。

 プログラムが必要とする「全てのメモリ空間」のうち、「今」必要な部分だけは実メモリに置き、今必要でない部分はディスク・スペース上に置いて、CPU が参照する時だけ、必要な部分を実メモリ上に読み出してくればよい……これが仮想記憶技術の基本発想です。

 「今はディスクにある『これから必要になる部分』」を実メモリ上に読み出す時は、前もって、「今、実メモリにある部分」を、ディスクに退避させねばなりません。
 この読み出し、退避の単位を「ページ」と呼び、実メモリ→ディスクの退避動作を「ページアウト」、ディスク→実メモリの読込動作を「ページイン」と呼びます。 また、ページアウトとページインの両動作を総合して、ページングと呼びます。
(OS によっては、ページングファイルという特別なファイルが、ディスク上に作られる事がありますが、これはページアウト、ページインの対象となる、つまりページを記録するためのファイルです)

 「プログラム実行に必要なメモリのうち、『今』必要な部分だけを実メモリに置く」のですから、実行したいプログラムが必要とするメモリ量が少なければ、実メモリだけで済んでしまい、ページアウトは発生しません。
 しかし、プログラム実行に必要なメモリ量が、実メモリを越えていると、ページアウト、ページインが頻繁に起こり、処理速度はかなり遅くなってしまいます(それでも、プログラムの実行が出来なくなるわけではありません)。

 「PC の性能アップにはメモリを増やせ」と言われるのは、ページングの減少が期待出来るからです(絶対に効果が出るとは言い切れませんが、一定の効果は期待できます)。

 

仮想メモリの階層の模式

各アプリケーション、プログラム
「全て」は仮想メモリ空間に置かれるが、「その時」に実行可能なのは実メモリに在る部分のみ。

CPU
実メモリに在るものしか実行出来ないが、実メモリアドレスは知らず、仮想メモリアドレスで実メモリの内容をアクセスする。

仮想メモリ空間
OS と動的アドレス変換機構が協調して作り出される、仮想メモリアドレスでアクセスされる実メモリ

動的アドレス変換機構
CPU やプログラムに対して「仮想メモリアドレスが割り振られた実メモリ空間」、すなわち仮想メモリ空間を見せる。

実メモリ空間
実際にコンピュータに搭載されているメモリ。実メモリアドレスが割り振られている。

ディスク空間
ページという単位でメモリの退避内容が記録される。OS の働きによりページアウト、ページインされる。

 

動的アドレス変換機構の働き

 上記模式の通り、仮想メモリとは、動的アドレス変換機構が「作り出す」、「巨大なメモリのイメージ」です。
 たとえば 32ビット OS では、1プログラムが使える仮想メモリアドレスは 0 から 4G-1 まであるのですが、実メモリが 512MB しか無ければ、実メモリアドレスは 0~512M-1 しかありません。

 プログラムの実行が、アドレス 512M-1 まで進んだら、ページアウトで実メモリの現状が保存され、次の部分がページインされますが、継続実行が「実メモリのアドレス 0 から」では、おかしな話になってしまいます。
 この場合、実行したいのは、「アドレス 512M 目以降」です。 しかし 512MB しか実メモリを積んでいなければ、512M という実アドレスは有りません。

 そこで、32ビット OS の動的アドレス変換機構は、アドレスを 0~4G-1 までだ、として(仮想メモリアドレス)、CPU に対しても、その仮想メモリアドレスを見せます。

 CPU が実行・参照したいアドレスが実メモリの範囲を越えていても、動的アドレス変換機構は、実メモリ仮想メモリアドレスで参照出来るようにして、CPU に見せるのです。

 先の例では、動的アドレス変換機構は、実メモリのアドレス 0 を、仮想メモリアドレス 512M に変換して、CPU に見せるわけです。 このおかげで、CPU は実メモリを「越えた」ことを認識する事すら無く、プログラムをどんどん実行して行けるのです。

 

ページングの契機

 上記までの説明では、「プログラムの実行が、アドレス 512M-1 まで進んだら、ページアウトして」……なんて、さらっと書いておりますが、そもそも、限界のアドレスまでプログラムの実行が進んだ事は、どのように分かるのでしょうか。

 これは、CPU に備わった「例外」(または「割り込み」)と呼ばれる仕組みによります。

 コンピュータ技術やプログラミングで使われる「例外 fault」とは、通常のプログラム実行動作とは異なる、ある種の特殊な状況が発生した時、CPU がそれを関知して、特定のプログラムを呼び出すという仕組みです。
(この事を「割り込み interrupt」という言葉で表現する事もあります)

 たとえば、「ゼロ除算例外」という例外があります。 これは、ゼロによる割り算が行われた時に発生する「例外」で、この例外が発生すると、CPU は、今実行しているプログラムを直ちに中断して、「ゼロ除算例外が発生した時」用の、特定のプログラムを実行します。
 他にも、タイマーが特定の値に達したという「例外」や、マウスが動いたという「例外」など、様々な例外が有ります。

 仮想記憶をサポートするシステムでは、プログラムの実行が実メモリ空間を越えた時、「ページ例外 page fault」という例外が発生します。
 各種の例外はソフトウェアから発生させる事も出来るのですが、ページ例外はソフトウェアでは難しいので(※1)、仮想記憶を使うためには、ページ例外をサポートするハードウェアを使うのが普通です。

※1 ソフトウェアがページ例外を発するのが難しい理由は少なくとも 2つ有る。
 1つは、全てのソフトウェアが、常に「境界」のアドレスを実行しているかどうかを見張るようにプログラミングするのはナンセンスという事である。
 もう 1つは、「境界」アドレスはシステムの構成によって変わるので、それをプログラムで検知するのもまたナンセンスであるという事だ。 実メモリのサイズにかかわらず、CPU の実行が実メモリを越える時に例外を出すのは、ハードウェアなら、より容易に実現出来る。

 ページ例外が発生すると、「ページ例外が発生した時」用の、特定のプログラムがただちに実行されます。 この「特定のプログラム」は OS の中に在り、現状の実メモリのページアウトと、ページインを実行し、そして何事も無かったかのように「元のプログラム」実行に復帰します。

 

仮想メモリ動作の模式

1.プログラムの実行が、実メモリの限界に差し掛かる。
(プログラム実行そのものは仮想メモリアドレス上で行われている)

2.ハードウェアがそれを検知し、ページ例外を発生させる。
(実行されているプログラム自身は、その事を「知らない」)

3.例外を受け取った CPU は、ただちにプログラム実行を一時中断し、ページングを行うプログラム(OS の中にある)を実行開始する。

4.現在の実メモリ内容をページアウトする。

5.「次」のページを、実メモリにページインする。

6.ページング・プログラム終了。

7.CPU は、中断した「元のプログラム」に復帰する。

8.元のプログラムは、中断された所から再び実行される。
(元のプログラムは、中断された事すら「分からない」)

 上記の流れのうち、3.から7.までは、OS の仕事です。
 また、ページングにより「実行すべき実メモリのアドレス」が 0 に戻ったり、ページアウト前とはかけ離れた実アドレスに飛んだりしても、動的アドレス変換機構が「然るべき(連続した)仮想メモリアドレス」を自動的に計算して提供するので、実行されているプログラムは「何も知らずに」仮想メモリアドレス上での実行を続けていく事が出来ます。

 

おわりに

 仮想記憶は、私達が PC を使う時に、ほぼ必ず使っている、「縁の下の力持ち」です。 普段、仮想記憶を意識する事はほとんどありませんが、この仕組みについて少しでも理解する事は、PC をより賢く快適に使う事につながるでしょう。

 

参考

http://itpro.nikkeibp.co.jp/article/COLUMN/20071107/286632/
(32ビット Windows の仮想記憶について、本ノートより具体的な説明がある)
http://ja.wikipedia.org/wiki/仮想記憶
(仮想記憶についての全般的な記事で、本ノートより専門的な説明がある)
http://ja.wikipedia.org/wiki/ページフォールト
(ページ例外について、本ノートより専門的な説明がある)

(転載以上)