mmap() を単なるファイルとのマップというのは概要としては良いんですが、技術者として見るとちょっと雑ですかね。
mmap() は OS カーネルのアルゴリズムを使うので、具体的なデータフェッチの方式は各 OS の実装依存になります。
でもスワップメモリーのようなスワップアルゴリズムのように絶えず IN/OUT を繰り返すような複雑なものは想定しなくても良いでしょう。
あくまで mmap() はディスクとマッピングしてくれるといっても基本的にはメモリーにコピーしないと使えないから、まあ、メモリーと同じです。
通常のメモリーと同じということは、解放もしてやらんといけないので munmap() というマッピングを解除・解放するための関数もあります。
mmap() 関数で一気に数百 GB を使おうとすりゃ、そりゃ DRAM に入り切らずにスワップに漏れちゃうのは仕方ないですが、それであればメモリー内で作業していても同じ条件「デス」よね?
mmap() 関数を呼び出してもディスクからデータをコピーしていないならマップされたメモリー領域は空のままです。
これ重要なんで繰り返しますね。
ディスクとメモリーをマップするだけでは、メモリーにデータはコピーされないので、未使用の段階では空の状態です。
空のメモリー領域(ページ)にアクセスしようとすると、アドレスにデータが存在しないためページフォルト( Page Fault )が発生します。
このページフォルトをカーネル内のハンドラ( page fault handler )が捕捉すると、データがコピーされます。
くどいですが、もう一度前の項目の図を見てみましょうね。
図のように mmap() は Linux のカーネルの機能を使ってディスクとのマッピングを行うのですが、重要な点はアプリケーションで使うタイミングです。
アクセスしようとしたデータが存在しないならフォルトハンドラが例外を捉えて、そこから
read() 関数を使うならメモリーに一旦コピーする事が必要ですが mmap() の場合は使用するたびにメモリーにコピーを行います。
MAP_PRIVATE では mmap() をしただけでは基本的にメモリーは空のままです。
しかしマップされたデータにアクセスしようとするとページフォルトが発生し、それをカーネルのハンドラが捉えてディスクからメモリーへのコピーをしてくれます。
一度コピーされると、メモリーに入っているので使えるようにします。
このコピーの実装については copy-on-write 方式が使われてるそうです。
COW(copy-on-write)は典型的なレイジー最適化(lazy optimization)です。
なぜならコピーが本当に必要になる瞬間にまでコピーを行わないため、プロセスの読み込み部分のコピーを省けるからです。
てなことで Copy-on-write を理解できていれば mmap() 関数を使ったアロケーターの設計にも役だつでしょう。
この項目もたぶん存在意義があるんですよ…
(´・ω・`)
ただ mmap() 関数によるアロケーターは C++ に特化した人からすると BOOST があるので、あまり受けは良くないと思います。
なのでこういうコンセプトがベースとなる Linux であるんだ程度の理解があればよろしいんじゃないですかね。
(・∀・)
ああ、それとスワップアルゴリズムは OS によるでしょうね。
Copyright 2018-2019, by Masaki Komatsu