第77章 MAP_PRIVATE の Copy-On-Write

目次

77.1. fork() で MAP_PRIVATE の Copy-On-Write を検証

 mmap() を単なるファイルとのマップというのは概要としては良いんですが、技術者として見るとちょっと雑ですかね。

 mmap() は OS カーネルのアルゴリズムを使うので、具体的なデータフェッチの方式は各 OS の実装依存になります。

 でもスワップメモリーのようなスワップアルゴリズムのように絶えず IN/OUT を繰り返すような複雑なものは想定しなくても良いでしょう。

 あくまで mmap() はディスクとマッピングしてくれるといっても基本的にはメモリーにコピーしないと使えないから、まあ、メモリーと同じです。

 通常のメモリーと同じということは、解放もしてやらんといけないので munmap() というマッピングを解除・解放するための関数もあります。

 mmap() 関数で一気に数百 GB を使おうとすりゃ、そりゃ DRAM に入り切らずにスワップに漏れちゃうのは仕方ないですが、それであればメモリー内で作業していても同じ条件「デス」よね?

 mmap() 関数を呼び出してもディスクからデータをコピーしていないならマップされたメモリー領域は空のままです。

 これ重要なんで繰り返しますね。

 ディスクとメモリーをマップするだけでは、メモリーにデータはコピーされないので、未使用の段階では空の状態です。

 空のメモリー領域(ページ)にアクセスしようとすると、アドレスにデータが存在しないためページフォルト( Page Fault )が発生します。

 このページフォルトをカーネル内のハンドラ( page fault handler )が捕捉すると、データがコピーされます。

 くどいですが、もう一度前の項目の図を見てみましょうね。

img/mmap_page_fault.png

 図のように mmap() は Linux のカーネルの機能を使ってディスクとのマッピングを行うのですが、重要な点はアプリケーションで使うタイミングです。

 アクセスしようとしたデータが存在しないならフォルトハンドラが例外を捉えて、そこから

 read() 関数を使うならメモリーに一旦コピーする事が必要ですが mmap() の場合は使用するたびにメモリーにコピーを行います。

 MAP_PRIVATE では mmap() をしただけでは基本的にメモリーは空のままです。

 しかしマップされたデータにアクセスしようとするとページフォルトが発生し、それをカーネルのハンドラが捉えてディスクからメモリーへのコピーをしてくれます。

 一度コピーされると、メモリーに入っているので使えるようにします。

 このコピーの実装については copy-on-write 方式が使われてるそうです。

copy-on-write( COW )
プロセスの fork() をする際に完全なプロセスの複製を作るのではなく、リソースをどのタイミングでコピーするかを決める方式です。例えば fork() 関数によって新たな子プロセスを生成すと大昔にはページ毎に全ての内部構造とプロセスアドレス空間のコピーが行われましたが、このコピーコストは馬鹿にならないものでした。それに対し Copy-On-Write では、複数の fork() されたプロセスが同じ内容のリソースを読み込みアクセスする場合にはリソースの重複コピーはされず、リソースを指すポインターが与えられるようにしました。ですが同じリソースに対して変更・書き込みをしようとすると、ポインターの代わりにデータがコピーされます。データの変更や修正を加えようとする時だけデータがコピーされますが、他のプロセスはオリジナルの情報をそのまま参照することができます。

 COW(copy-on-write)は典型的なレイジー最適化(lazy optimization)です。

 なぜならコピーが本当に必要になる瞬間にまでコピーを行わないため、プロセスの読み込み部分のコピーを省けるからです。

 てなことで Copy-on-write を理解できていれば mmap() 関数を使ったアロケーターの設計にも役だつでしょう。

 この項目もたぶん存在意義があるんですよ…

 (´・ω・`)

 ただ mmap() 関数によるアロケーターは C++ に特化した人からすると BOOST があるので、あまり受けは良くないと思います。

 なのでこういうコンセプトがベースとなる Linux であるんだ程度の理解があればよろしいんじゃないですかね。

 (・∀・)

 ああ、それとスワップアルゴリズムは OS によるでしょうね。

Copyright 2018-2019, by Masaki Komatsu