mmap は Linux でファイルとメモリーのアドレスを紐付けて(マップして)、ファイルをメモリーかのようにアクセスできるようにしてくれる関数です。
基本的な用途としてはメモリーの中身をハードディスクの中にあるファイルにバックアップを高い頻度でとりたい場合ですかね。
もしくはディスク内のファイルを配列・バッファーのように読み込みたいとかです。
まあ必ずしもファイルをマップする用途に限定されるわけじゃないですが、ここはお急がしい読者さんのために分かりやすい定義でいきましょう。
ここで説明している「ファイルマッピング」の他にも「無名マッピング( Anonymous mapping )」というものがあります。
それでマップとは「なんなのら?」とお考えの読者は以下のイメージを見てくださいね。
この図の「紐付けられた領域」は「マッピングされた領域」と考えればいいんです。
つまりプロセスアドレス空間とファイルのデータが紐付けられているってことです。
それでプロセスアドレス空間の内約については以下の図に示しますね。
プロセスアドレス空間というのは別名で仮想アドレスとも言います。
x86 アーキテクチャでは仮想アドレスはリニアアドレス(Linear Address)とも呼ばれてます。
32 ビットの Linux であれば 4 GB が割り当てられ、うち 1 GB がカーネル部分となります。
mmap でのマップの考え方としてはページテーブルが仮想アドレスから物理アドレスの翻訳(アドレストランスレーション)されるのを見ておくと良いでしょう。
(開始 2 ビットを使う)一段テーブルも(開始 4 ビットを使う)二段テーブルもアドレストランスレーションの作法が異なるだけで最終的には物理アドレスに紐付けられてますよね。
Linux ではページテーブルは以下のような三段構成になっています。
mm_struct は後で詳しく説明しますがメモリー記述子というオブジェクトでして、メモリーマッピングについての情報を保持します。
PGD と PMD と PTE についてはアドレス階層の名前なのであまり深く考えなくても大丈夫です。
最終的には解決したかった page オブジェクト、そしてそこから物理テーブルにたどり着きます。
ちなみに Linux 2.6.11 以降では四段構成( pgd, pud, pmd, pte )となっています。
mmap のプロセスアドレス空間でも、同様な考え方でページテーブルを使って物理アドレスを検索します。
当然マップをしたらメモリー内のページにロードしたり、メモリー内のページに読み書きすることになりますね。
ただ後の項目で説明しますが mmap ではページ内にデータがないので OS がデータをアクセスのたびにディスクからメモリーにロードしたりします。(使いすぎるとスワップメモリーに漏れるのでディスクとメモリーの区別はグダグダになりますけどね)
それで OS の処理するイメージとしては以下のようにページフォールト( Page Fault )の例外をOSが処理してからディスクからメモリーへのロードが発生します。
プロセスアドレス空間から物理アドレスへいくまえに MMU (メモリー管理ユニット)というCPU側の装置でデータが無いことをを検知し OS 側のページフォルトハンドラー( Page Fault Handler )がディスクから物理メモリーへのコピーをしてくれます。
ちなみに2つ以上のプロセスから、ファイルにアクセスしたい場合は以下のようにします。
このようにファイルをプロセスアドレス空間と紐付けてくれるわけです。
ファイルマッピングについては、ちょっと大雑把なまとめだとは思うんですが、特にマジックじみた事はしていないので図示が可能だという認識ぐらい持ってもらえば大丈夫です。
Copyright 2018-2019, by Masaki Komatsu