【メモ】UNIX V6コードリーディング(メモリ周りの整理/まとめ)
今回の内容
前回まではトラップハンドラについて読み進めていました.
前回とは大きく内容が変わってメモリ周りの話を整理していきたいと思います(先にシグナルを読んでもよかったかも). 実は先々週あたりの勉強会を思い出して書いているので内容が確かじゃないかもしれないです. 書籍のページ数が結構飛び飛びになるので, 適宜どのあたりの話をしているか書いていきたいと思います.
アドレス変換(p52〜p55)
仮想アドレスから物理アドレスへの変換はp52に書かれていますが, 1点だけ補足を. APRが8つあるということは, 逆に言うと仮想アドレス空間は8Kバイト(= 213)毎に違うAPRを参照して物理アドレスへの変換を行うことになります. p50に書かれている「データ領域はテキストセグメントの後ろの8Kバイト刻みのアドレスに割り当てられます」の理由はここにあります. テキストセグメントとデータセグメントは物理アドレス上では連続していません. つまり, 同じAPRに割り当てられません. このあたりはアドレス変換の仕方についてよく考えると確かにそうなるなぁという感じになります.
仮想アドレス空間(p48〜p52)
細かいメモリの操作をする箇所を読むにあたって, 仮想アドレス空間と物理アドレス空間がどのようにマッピングされているかを理解しておくと非常に理解が進みます. 意識しておいたほうが良さそうなポイントをいくつか.
- テキストセグメントとデータセグメントは物理メモリ上では別々の連続した領域.
- テキストセグメントはプロセス間で共有される.
- データセグメントはPPDA, データ領域(ヒープ領域を含む), スタック領域からなる.
- PPDAにはuser構造体とカーネルスタック領域が置かれる.
- PPDAはユーザープロセスの仮想アドレス空間にマッピングされない(ユーザー空間からはアクセスできない).
- データ領域とスタック領域は物理アドレス空間では連続している.
- ヒープ領域はアドレスが大きくなる方向に, スタック領域は小さくなる方向に伸びていく.
- スタック領域は仮想アドレス空間の一番上位(0xffff)に割り当てられている.
- 物理アドレス上でヒープとスタックがぶつかった場合は拡張が行われる(
expand
関数).
仮想アドレス空間の操作
仮想アドレス空間に対する操作を行っている(と思われる箇所)をピックアップしてみました.
仮想アドレス空間のマッピングの変更はestabur
, sureg
あたりで行われるようです(p103〜).
細かいところは読めてないですが, estabur
でuser構造体にAPRにセットする情報を格納, sureg
でuser構造体の情報に従ってAPRの値を操作するようです.
データ領域の拡張はbreakシステムコールで実現されます(p118). Cライブラリのmallocなどの内部で使用されるようです. 長年疑問だったmallocした時のメモリはどこから出てくるのかに対する答え(?)が少し得られたようで, 個人的には結構面白いと感じました. 実際にはOS側はデータ領域を拡張/縮小しているだけで, その他の諸々はCライブラリのmallocがやってくれているという感じなんでしょうか?
スタック領域の拡張はトラップハンドラの中で行われます(p176, grow
).
ちなみに, 実行プロセスのPPDAはカーネル用のAPR6から参照できるようになっており, プログラム中ではu
という変数で参照できます(p54一番下).
この切り替えはコンテキストスイッチの際にしれっと行われています(p78).
当然ですが, このときにユーザー空間のマッピングが変更されます.
おそらく, estabur
とsureg
が分かれている理由はこの辺にあって, コンテキストスイッチの際はuser構造体に格納された情報からマッピングし直すだけなのでsureg
だけが呼び出されてます.
(細かく中を読めていないので間違ってるかもしれないですが...)
まとめ
メモリ周りをいろいろと整理してみましたが, これを一発で理解するのは無理ですね(). ただ, いろいろと考えながら読んでみると本当によくできているなぁと思わされることばかりです.
次回の予定
スワッピングあたり?