このテキストは、運営している韓国のブログを日本語に翻訳したものです。
韓国のブログ:https://yunsuu.notion.site/e379eccd32c545419f0651f743c12c13?v=35310b282de24cc5a292fe45cc498a32&pvs=74
この記事は「Operating Systems: Three Easy Pieces」を読んでまとめた本です。
著者が無料で公開しているので、興味のある方はぜひ読んでみてください。
本にある良い問題は解いてgithubにアップロードしています。
github:https://github.com/yunsuu/ostep-homework-solution
本のリンク:https://pages.cs.wisc.edu/~remzi/OSTEP/
この記事の主な目的は、仮想アドレスがどのように物理的なアドレスに変換されるかのプロセスを理解することです。次のような仮定を設定して、概念を説明します。これらの仮定を徐々に緩和して、現実を反映できるように説明していきます。
仮定
- ユーザーのアドレス空間は物理メモリに連続して配置される必要があります
- アドレスのサイズはあまり大きくない
- アドレス空間は物理メモリサイズより小さい
- 各アドレス空間のサイズは同一である
仮想メモリ実装の目標
透明性(Transparency)
- OSは、実行中のプログラムが仮想メモリの存在を認識せず、専用の物理メモリを所有しているかのように認識させる必要があります。
効率性
- 当然のことながら、できるだけ効率的であるべきです
保護
- プロセスを他のプロセスから保護する
- OS自体もプロセスから保護する必要がある
- これを実装する方法は、各プロセスのメモリを隔離することです。
例として、このコードを見てみましょう。
void func() {
int x = 3000; // thanks, Perry.
x = x + 3; // line of code we are interested in
...
このコードの部分で、x = x +3の部分をアセンブリ言語で見ると、次のようになります。
128: movl 0x0(%ebx), %eax ;load 0+ebx into eax
132: addl $0x03, %eax ;add 3 to eax register
135: movl %eax, 0x0(%ebx) ;store eax back to mem
各プロセスの仮想メモリが16KBとすると、
実際のメモリには、次の図のように分割された仮想メモリにアセンブリ言語のコードが配置されています。
仮想メモリの実装の目標は透明性です。つまり、プロセスがどこから命令を保存するかを気にせず、それはOSの仕事です。
ここで考えてみるべき点は、OSがどのようにしてプロセスを知らずにどこに配置すれば16KBのメモリを連続的に確保する開始点を見つけることができるのか、ということです。
動的(ハードウェアベース)再配置
これは、CPU内の基底レジスタと界(bound)レジスタの2つで実装されるアドレス変換技術です。
これらのレジスタは、各CPUに1つずつしか存在しません。
物理アドレス = 仮想アドレス + ベースレジスタ値
次の公式を見ると、基底レジスタの使用法が大体理解できるでしょう。
界レジスタの使用法は、どこまでをプロセスの終了とするかです。2つの方法があります。1つ目は、プロセスの仮想メモリのサイズを保存する方法、2つ目は、上の図のように、仮想メモリをどこまで指定するかの「終了」の情報を持つ方法です。
これら2つのレジスタは、メモリ管理を助けるため、MMU(Memory Management Unit)と呼ばれることもあります。
さらに、アドレス変換プロセスはCPUユーザーモードではなく、CPUカーネルモードで実行されます。なぜそうなるのかは、簡単に考えてみればわかります。ユーザーモードでMMUレジスタを操作できると考えてみてください。つまり、ユーザーがプログラミングでMMUを変更できるということです。操作が可能になれば、全体的なプロセススケジュールが混乱するでしょう。
OSが考慮すべき点
どこが空のメモリ空間なのか?
「空きスペースリスト」を使用して、OSはこれを確認します。プロセスに仮想メモリを割り当てる必要があるとき、リスト内のスペースを検索して割り当てます。
終了したプロセスのメモリ回収
プロセスが正常に終了したか、異常な方法で終了した場合、プロセスが割り当てていたスペースを空きスペースリストに戻し、次のプロセスが使用できるようにします。
コンテキストスイッチ時のMMU管理
プロセスが切り替わるとき、ベース、バウンドレジスタは他のCPUレジスタと一緒に切り替わります。
例外処理
プロセスがカーネルモードの命令を実行したり、割り当てられた仮想メモリの範囲を超えてアクセスしようとしたとき、例外処理を行う機能が必要です。
全体的なフローチャート
ブートアップ時
実行時
実行時に注目すべき点
- メモリアドレス変換プロセスでは、OSは介入しません。
- プロセスBでbad loadが発生した場合、カーネルモードでプロセスBを終了します。