コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
mmap とメモリマップトファイル
mmap とメモリマップトファイル
このレッスンで分かること
mmapはファイルやデバイスをプロセスの 仮想メモリ空間に貼り付ける システムコールです- 一度マッピングすればファイル I/O が ポインタ操作 で済み、
read/writeの往復が不要になります- 大規模ファイル、共有メモリ、実行ファイルのローディングまで、現代 OS が頼り切っている仕組みです
mmap とメモリマップトファイル とは
mmap とメモリマップトファイル。本レッスンでは、mmap とメモリマップトファイル の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
mmap の発想
通常のファイル読み書きは下記の流れになります。
read(fd, buf, n)でカーネルに依頼- カーネルがファイルからユーザーバッファ
bufにコピー - ユーザー側がデータを使う
このコピーが大きなファイルでは無視できないコストになります。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 しか読みません。
図解
マッピングの種類
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 つができることを確認しましょう。
- mmap の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. mmap とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン