コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB

mmap とメモリマップトファイル

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

mmap とメモリマップトファイル

このレッスンで分かること

  • mmap はファイルやデバイスをプロセスの 仮想メモリ空間に貼り付ける システムコールです
  • 一度マッピングすればファイル I/O が ポインタ操作 で済み、read/write の往復が不要になります
  • 大規模ファイル、共有メモリ、実行ファイルのローディングまで、現代 OS が頼り切っている仕組みです

mmap とメモリマップトファイル とは

mmap とメモリマップトファイル。本レッスンでは、mmap とメモリマップトファイル の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

mmap の発想

通常のファイル読み書きは下記の流れになります。

  1. read(fd, buf, n) でカーネルに依頼
  2. カーネルがファイルからユーザーバッファ buf にコピー
  3. ユーザー側がデータを使う

このコピーが大きなファイルでは無視できないコストになります。mmap はファイルのページを 仮想メモリページに直接マッピング することで、コピーを 1 回省きます。

c

#include <sys/mman.h> #include <fcntl.h> int fd = open("data.bin", O_RDONLY); size_t len = 1024 * 1024; // 1 MB void *p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); // ポインタ p[0], p[1], ... がそのままファイル内容を指す

p[i] にアクセスすると、その時点で ページフォルトが発生し、必要なページだけディスクから RAM に読み込まれます(遅延読み込み)。1GB ファイルでも、実際に触るのが 4KB だけならその 4KB しか読みません。

図解

diagram (will load when visible)

マッピングの種類

mmap の引数で挙動が変わります。

フラグ意味
MAP_SHARED書き込みがファイルに反映される(複数プロセスが共有可)
MAP_PRIVATE書き込みは Copy-on-Write、自分の中で完結
MAP_ANONYMOUSファイルではなく、初期化済みゼロ領域を mmap(malloc の内部実装で使用)
PROT_READ PROT_WRITE PROT_EXECアクセス権

MAP_SHARED を 2 つのプロセスから同じファイルに対して行えば、共有メモリ として使えます。書き込みは即座に相手にも見えます。

具体例 (Python)

Python

import mmap, os with open("large.bin", "r+b") as f: size = os.path.getsize(f.name) with mmap.mmap(f.fileno(), size) as mm: # ファイル全体を bytes のように扱える if mm[:4] == b"\x7fELF": print("This is an ELF binary") mm[100:104] = b"\xde\xad\xbe\xef" # 即座にファイルに反映

mm[:4] で先頭 4 バイトを読み、mm[100:104] = ... で書き換える――まるでメモリ上の配列のように扱えます。

どこで使われているか

用途説明
実行ファイルのロードOS は ELF / Mach-O / PE をプロセス起動時に mmap する
共有ライブラリ.so .dylib .dll も mmap で読まれ、複数プロセスで共有
データベースSQLite、LMDB、RocksDB が mmap ベース
大規模ログ・コーパス処理全部 read するより 100 倍速いことも
malloc の大きな確保glibc は閾値超えで mmap を使う

トレードオフ

  • ランダム I/O が多い場合は逆に遅く なることがあります。ページフォルトのたびに同期的にディスクを読むため、read で先読みするより不利な場合も
  • mmap した領域は OS のページキャッシュと一体化 するので、ファイルが他のプロセスから書き換えられると見ているデータが変わります(一貫性に注意)
  • 64bit でも仮想アドレス空間は無限ではない。何 TB ものファイルを全部 mmap しようとすると失敗する場合があります

よくある誤解

  • 「mmap すれば常に速い」は誤解で、データを 1 回だけ順に読むだけなら read でも体感差は小さいです
  • 「mmap した直後にデータが全部 RAM に乗る」も誤解で、実際は 触ったページだけ ロードされます

やってみよう

pmap <PID>(Linux)で、自分のプロセスが mmap した領域一覧が見られます。/usr/lib/libc.so.6 のような共有ライブラリが必ず含まれているはずです。実行ファイル自体も mmap されているのが分かります。

よくある質問

Q. mmap と read/write はどう使い分ける?

A. 大きなファイルをランダムアクセスしたい場合や、複数プロセスで同じファイルを共有したい場合は mmap が有利です。一方、ファイルを先頭から順番に 1 度だけ読むだけなら read の先読みと大差なく、むしろシンプルに書ける read/write の方が適切です。

Q. MAP_SHARED と MAP_PRIVATE の違いは?

A. MAP_SHARED はプロセスが書き込んだ内容がファイル本体に即座に反映され、同じファイルをマッピングした他のプロセスにも見えます。MAP_PRIVATE は Copy-on-Write で自プロセス内にのみ変更が残り、ファイルには反映されません。実行ファイルのロード時は MAP_PRIVATE が使われるため、コードページを書き換えても元ファイルは壊れません。

Q. munmap や msync は必要?

A. プロセス終了時に OS がすべてのマッピングを解放しますが、長時間動き続けるプロセスでは不要になった領域を munmap で明示的に解放しないと仮想アドレス空間を圧迫します。MAP_SHARED で書き込んだ内容をディスクに確実に反映させたい場合は msync を呼んでください。呼ばなくてもいずれカーネルがフラッシュしますが、タイミングは保証されません。

次のレッスン

次は ガベージコレクション概要 で、不要になったメモリを自動で回収する仕組みを学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. mmap の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. mmap とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン