仮想記憶が誕生した流れ

初めまして、ALTURA X インターン生の藤嶋と申します。

Dockerについて学習していた時にふと出てきた、仮想メモリという言葉について調べていたところ、主に2つの説明がありました。
それが、「仮想メモリは、離れてしまっている物理アドレスを連番の仮想アドレスとして使えるようにするもの」や「ディスクを使用することによって、メモリの容量を仮想的に増やせるもの」です。
そこで、私はどちらが仮想記憶が誕生した本質的な理由なのかが気になり調べてみました。

今回はこの調べた結果を、仮想記憶が誕生したプロセスを辿りながらまとめていこうと思います。
また、記事作成に当たって、主にこちらを参考にさせていただきました。よろしければ、ご覧ください。
15群(○○○)-8編


多重度の向上を目指して

コンピューターが誕生してから、DRAMの性能が急速に向上した1980年代までの約40年間、メモリ容量の制限が続きました。

そのため、メモリ不足によって多重度を高めることができず、実行可能なプロセスが少ないため、CPUの性能を100%使う事ができません。
よって、当時のエンジニアたちはいかにして多重プログラミングの多重度を高め、CPUの使用率を100%にできるかという目標を掲げ、さまざまな創意工夫を行ってきました。

この、創意工夫によって生まれたのが仮想メモリです。

未参照領域という問題

多重プログラミングを行うには、複数のプログラムを主記憶内にローディングしておく必要があります。そのため、それぞれのジョブに、メモリ領域を分割した中の一つの領域を割り当てる必要があります。

この実現方法として一番簡単なものに、静的分割方式が挙げられます。
メモリ領域に固定的なパーティションを作成しておき、それをジョブに割り当てる方式です。
しかし、これでは割り当てられたメモリ領域内に未参照領域が生まれてしまいます。

未参照領域は、パーティション内、ジョブ要求メモリ領域内、プログラムやデータ領域内にそれぞれ生まれます。
固定長パーティションの場合は、ジョブが要求するサイズ以上のパーティションが割り当てられます。そのため、必然的にパーティション内に空き容量が生まれてしまいます。

また、ジョブが要求するメモリサイズは、プログラマが自分のジョブを実行するために必要十分な大きさを指定するために,一般的には少し余裕をもった値となるため、ジョブ要求メモリ内にも、空き領域が生まれます。

さらに、ほとんど使用されないが、常時ローディングされていないといけない異常処理のプログラムであったり、将来拡張するために確保されているデータ領域も含まれているため、プログラムやデータ領域内に、空き領域が生まれます。

このように、ジョブに割り当てられるメモリ領域の中には様々な未参照領域が含まれています。多重プログラミングの多重度を向上させるためには、これらのジョブに割り当てられる未参照領域を取り上げ、その分を他のプログラムに割り当てられるようにする必要があり、これらを目的として多くの工夫がなされてきました。

動的分割法

静的分割方式では多重プログラミングは実現できますが、メモリ節約はできません。そのため、ジョブが要求するメモリ容量と一致するパーティションを実行時に作成する、動的分割方式が提案されました。

動的分割方式によって、パーティション内の空き領域が生まれないため、メモリを節約しほかのジョブに割り当てることができます。しかし、残りの2の未参照領域を節約することはできず、またフラグメンテーションという新しい問題が出てきてしまいました。

フラグメンテーションの発生

当時はジョブをためて一括処理するバッチ処理が主流であり、ため込んだたくさんのジョブたちの中には要求されるメモリの量が小さいジョブが多く存在しました。
そのため、要求されるメモリ量の小さなジョブから処理を行うことによって、処理の効率化を行うために、それぞれのジョブに対して必要資源量に応じてジョブクラスが作られ、資源量の小さいジョブから処理が行われていきました。

しかし、動的割付によって小さなジョブをたくさん実行すると、結果としてメモリに小さな空きパーティションがたくさんできてしまい、それぞれの空きパーティションのサイズが足らず利用できなくなってしまいました。これがフラグメンテーションです。

このフラグメンテーションの原因は、ジョブに対するメモリの割付は連続的な領域でないといけないという制約です。
もし、この制約がなければ主記憶上の散らばった空き領域を寄せ集めて割り当てることができるため、多重度を向上させることができます。

ページング方式の誕生による仮想記憶の誕生

そこで、主記憶を一定の小さな単位に分割しておき、メモリへの要求に対して任意の未割当てのページを必要なだけ割り当てるという、ページング方式が開発されました。
ページング方式では、メモリを一定のサイズの領域(ページ)で区切り、物理的に離れているページを論理的に連続にした、論理アドレス領域をプログラマに与えます。そのため、メモリのフラグメンテーションに関係なく連続したアドレスをプログラマに提供できるようになりました。

離れている任意のページを連続して割りてることができるため、フラグメンテーションで生じた、小さすぎて割り当てられない領域がなくなり、メモリをより効率よく使用できるようになりました。このページング方式によって、連続的な論理アドレス空間である仮想メモリが実現されます。

ページング方式の拡張

さらに、ページング方式にページフォルトという機能を追加し、DATを拡張したオンデマンドページングによって、物理メモリの容量より大きな領域を提供できる仮想メモリが生まれました。

オンデマンドページングでは、プロセス実行直後には仮想的なメモリ領域は与えますが、主記憶のページを全く割付けません。プログラムの領域が読み出されるときに、論理アドレスを物理アドレスに変換し、物理メモリにページがローディングされます。つまり、参照された論理アドレスのページのみに、物理メモリのページが割り付けられてプログラムが実行されます。

そのため、参照されたページのみ、物理メモリに読み込むことができ、上の残りの2つの領域内(ジョブ要求メモリ領域内、プログラムやデータ領域内)の未参照領域が発生しません。
これによって、オンデマンドページングによってメモリ管理の課題であった、パーティション内、ジョブ要求メモリ領域内、プログラムやデータ領域内での未参照領域を解決することができました。

さらにオンデマンドページングでは、メモリが一杯になってしまった時に、将来参照がないと思われるページを探して解放します。解放されたページはページングファイルに書き込まれ、この操作をページアウトと呼び、反対にページングファイルのページがページフォルトによってメモリに読み込まれることをページインと言います。

また、似た言葉として、スワップインやスワップアウトがありますが、これは、多重度が高すぎてページインやページアウトの操作が多発してしまい、逆に性能が落ちてしまっている時に、一時的にスワップファイルにプロセスごと吐き出すことをスワップアウトと呼び、また多重度が低くなった時にメモリに戻すことをスワップインと言います。

このように、オンデマンドページングでは、ページイン・ページアウトと呼ばれる操作が可能になった事により、メモリの容量以上の容量を持つ仮想アドレス空間を使用できるようになりました。

こうして、最終的には未参照領域の発生という問題と物理メモリの容量以上のアドレス空間の提供が可能な仮想アドレスが誕生しました。

おわりに

今回は、誕生のプロセスや存在意義に重点を置いて学習を行いました。ただ、説明文を眺めるだけでなく、それが開発されたプロセスや歴史にも目を向けると、しっかりとした理解につながると感じました。
これからは、理解しにくいものはその誕生のプロセスや歴史についても学習を行い、しっかりと理解できるようにしていこうと思いました。



いいなと思ったら応援しよう!