仮想記憶について解説をしていきます。プログラムでどのようにメモリが管理されているか学べるようになっています。
仮想記憶とは
仮想記憶はプロセスがメモリにアクセスをする時に、物理的なメモリに直接アクセスしないで、仮想アドレスというアドレスを使って間接的にメモリにアクセスするプロセスのメモリ管理方法。
仮想アドレスから物理アドレス変換にはカーネル内に保存されているページテーブルという表を使う。
OSは物理メモリと仮想メモリを固定サイズのメモリの塊に分割する。仮想メモリの塊をページ、物理メモリの塊をフレームと呼んでいる。OSは仮想メモリページを物理メモリフレームに動的にマッピングしている。
ページテーブル内の1つのページに対応するデータをページテーブルエントリと呼んでいる。
仮想メモリが必要な理由
仮想メモリが必要な理由は、仮想メモリがなかった場合に以下の問題があるからです。
- メモリの断片化:プロセスが生成した後に、メモリの獲得と解放を繰り返すことでメモリの断片化(フラグメンテーション)が起きる
- マルチプロセスができない:複数のプログラムを動かそうとすると、開発者側が各プログラムの物理アドレスが重ならないように意識する必要がある。
- 不正な領域へのアクセス:プロセスがどのメモリにもアクセスしたら、データ破壊の恐れがある
これらを解決するために仮想メモリがあり、仮想メモリによって問題が解決される。
- 断片化されている物理メモリを集めて、仮想アドレス上では1つの領域に見せる
- どのプロセスでも仮想アドレスを見ることで、同じ物理メモリを見ることがない
- プロセスごとに専用の仮想メモリがあるため、他のプロセスのメモリにアクセスをすることがない
メモリの割り当て
動作中のメモリに新たにメモリを割り当てるにはmmapというシステムコールを使用する。
ただmmapを実行した直後は、新規メモリに対応する物理メモリは存在しない。その代わりにその新規メモリにアクセスがあったタイミングで物理メモリを割り当てる。これをデマンドページングという。デマンドページングを実現するために、メモリ管理システムはページに対応する物理メモリを割り当てているかの状態を持つ。
コピーオンライト
Linuxでは仮想記憶の機能を応用して、プロセス作成処理を高速化している。
fork関数を実行時に、親プロセスのメモリを子プロセスに全てコピーをしないでページテーブルだけコピーをする。この後に親子のプロセスで共有された物理ページアクセスができ、親子の一方のデータを更新する時に、ページ共有を解除して、それぞれのプロセス専用のページを持つ。
fork関数実行時ではなく、各ページへの書き込み時にデータをコピーする。これをコピーオンライトと呼ぶ。
コピーオンライトのおかげで、プロセスがfork関数を実行するときに、メモリを全てコピーする必要がなく、fork関数の高速化やメモリ使用量を減らせる。
下のイメージを例にすると、最初0~200まで親プロセスと子プロセスは共有の物理アドレスを見ています。子プロセスの100~200の物理アドレスのデータに更新が発生した時に、コピーオンライトが実行され、100~200の物理アドレスについて、親プロセスと子プロセスの共有が解除されて、それぞれ別の物理アドレスを見るようになる。
RSSの注意
psコマンドのRSSの値はプロセスが物理メモリを他のプロセスと共有しているかを気にしていない。各プロセスのページテーブルの中で、物理メモリが割り当てられているメモリの領域の合計をRSSの値としている。なので親プロセスと共有しているページに書き込んでコピーオンライトが発生しても、メモリの中身が変わるだけで、持っている容量が変わらないので、RSSの値は変わらない。
なので全プロセスのRSSの合計が物理メモリの総量を超えることがある。
理解度チェック
今回の内容がわかっているかの問題を作成しています。
問題をクリックすると、答えが表示されますので、今回の内容を理解できたかチェックをしてみてください。
まとめ
今回は仮想メモリ、コピーオンライトについて解説をしていきました。
低レイヤーについて、知識を深めることは開発者にとても大事なことです。このブログでは他にもCPUとメモリや、カーネルとシステムコール、プロセスの管理について解説をしている記事があるので、そちらも読んでみてください。
【おすすめ記事のリンク】
コメント