ファイル アクセスに mmap を使用する必要があるのはいつですか?

mmap 複数のプロセスが同じファイルから読み取り専用の方法でデータにアクセスしている場合に最適です。これは、私が作成する種類のサーバー システムでは一般的です。 mmap これらすべてのプロセスが同じ物理メモリ ページを共有できるため、多くのメモリを節約できます。

mmap また、オペレーティング システムがページング操作を最適化できるようにします。たとえば、2 つのプログラムを考えてみましょう。プログラム A 1MB を読み取ります malloc で作成するバッファへのファイル 、およびmmapsのプログラムB 1MBのファイルをメモリに。オペレーティング システムが A の一部をスワップする必要がある場合 のメモリ出力の場合、メモリを再利用する前に、スワップするバッファの内容を書き込む必要があります。 B で の場合、変更されていない mmap OS は mmap だった既存のファイルからページを復元する方法を知っているため、'd ページはすぐに再利用できます。 から。 (OS は、最初に書き込み可能な mmap をマークすることで、どのページが変更されていないかを検出できます。 'd ページを読み取り専用として、コピー オン ライト戦略と同様に、セグ フォールトをキャッチします)。

mmap プロセス間通信にも役立ちます。 mmapできます mmap'd で通信し、同期プリミティブを使用する必要があるプロセスで読み取り/書き込みとしてファイル 地域 (これが MAP_HASSEMAPHORE フラグは for) です。

1 か所 mmap 32 ビット マシンで非常に大きなファイルを処理する必要がある場合は、扱いにくい場合があります。これは mmap のためです プロセスのアドレス空間で、マップされているファイルの範囲全体に収まる十分な大きさのアドレスの連続ブロックを見つける必要があります。これは、アドレス空間が断片化され、2 GB のアドレス空間が空いていても、1 GB のファイル マッピングに収まる個々の範囲がない場合に問題になる可能性があります。この場合、ファイルを収まるようにするよりも小さなチャンクでファイルをマップする必要がある場合があります。

mmap のもう 1 つの厄介な問題の可能性 読み取り/書き込みの代わりに、ページ サイズのオフセットでマッピングを開始する必要があります。オフセット X でデータを取得したい場合 mmap と互換性があるように、そのオフセットを修正する必要があります。 .

そして最後に、読み取り/書き込みができる唯一の方法です 一部の種類のファイルを操作します。 mmap パイプや tty などには使用できません。


mmap() が利点ではないことがわかった領域の 1 つは、小さなファイル (16K 未満) を読み取る場合でした。ファイル全体を読み取るためのページ フォールトのオーバーヘッドは、単一の read() システム コールを実行する場合に比べて非常に高かった。これは、カーネルがタイム スライス内で完全に読み取りを満足できる場合があるためです。つまり、コードが切り替わることはありません。ページ フォールトが発生すると、別のプログラムがスケジュールされる可能性が高くなり、ファイル操作の待ち時間が長くなります。


mmap 大きなファイルにランダムにアクセスできる場合に利点があります。もう 1 つの利点は、バッファリングを気にすることなく、メモリ操作 (memcpy、ポインター演算) でアクセスできることです。バッファよりも大きな構造体がある場合、バッファを使用すると、通常の I/O が非常に困難になることがあります。正しく処理するのが難しいことが多いコードを処理するには、mmap の方が一般的に簡単です。とはいえ、mmap を使用する場合、特定のトラップがあります。 .人々がすでに述べたように、mmap セットアップには非常にコストがかかるため、特定のサイズ (マシンごとに異なります) にのみ使用する価値があります。

ファイルへの純粋なシーケンシャル アクセスの場合、madvise への適切な呼び出しはありますが、常により良い解決策とは限りません。 問題を軽減できます。

アーキテクチャ (SPARC、Itanium) のアラインメント制限に注意する必要があります。読み取り/書き込み IO では、多くの場合、バッファーは適切にアラインされ、キャストされたポインターを逆参照するときにトラップされません。

また、マップの外にアクセスしないように注意する必要があります。マップで文字列関数を使用していて、ファイルの末尾に \0 が含まれていない場合、これは簡単に発生します。最後のページが 0 で埋められるため、ファイル サイズがページ サイズの倍数でない場合、ほとんどの場合は機能します (マップされた領域は常にページ サイズの倍数のサイズになります)。