回答:
mmap
複数のプロセスが同じファイルから読み取り専用の方法でデータにアクセスしている場合に最適です。これは、私が作成する種類のサーバーシステムでは一般的です。 mmap
これらすべてのプロセスが同じ物理メモリページを共有できるため、メモリを大幅に節約できます。
mmap
また、オペレーティングシステムがページング操作を最適化できるようにします。たとえば、2つのプログラムを考えてみましょう。で作成したバッファにファイルA
を読み込むプログラムと、1MBのファイルをメモリに書き込むプログラムB。オペレーティングシステムがのメモリの一部をスワップアウトする必要がある場合は、メモリを再利用する前に、バッファの内容を書き込んでスワップする必要があります。場合任意の未修正のOSは、彼らがいた既存のファイルからそれらを復元する方法を知っているので、「Dページはすぐに再利用できるから「D。(OSは最初の書き込み可能なマーキングによって変更されないどのページを検出することができます読み取り専用として」Dページを引くとワンセグ障害と同様に、書き込みのコピー戦略を)。 1MB
malloc
mmaps
A
B
mmap
mmap
mmap
mmap
プロセス間通信にも役立ちます。することができますmmap
必要が通信し、その後で同期プリミティブを使用することのプロセスで読み取り/書き込みとしてファイルmmap'd
地域(これは何ですかMAP_HASSEMAPHORE
フラグのためです)。
mmap
32ビットマシンで非常に大きなファイルを操作する必要がある場合は、厄介なことが1つあります。これは、mmap
がプロセスのアドレス空間で、マッピングされているファイルの範囲全体に適合するのに十分な大きさの連続したアドレスのブロックを見つける必要があるためです。これは、アドレススペースが断片化した場合に問題になる可能性があります。2GBのアドレススペースが空いている可能性がありますが、その個々の範囲では1 GBのファイルマッピングに適合できません。この場合、ファイルを収まるようにしたいよりも小さなチャンクでファイルをマップする必要がある場合があります。
mmap
読み取り/書き込みの代替として考えられるもう1つの問題は、ページサイズのオフセットからマッピングを開始する必要があることです。オフセットでデータを取得するだけの場合はX
、そのオフセットを修正して、と互換性があるようにする必要がありますmmap
。
そして最後に、読み取り/書き込みは、いくつかのタイプのファイルを操作できる唯一の方法です。 pipesやttysmmap
などには使用できません。
MAP_HASSEMAPHORE
はBSDに固有です。
mmap()が有利ではないことがわかった1つの領域は、小さなファイル(16K未満)を読み取るときでした。ファイル全体を読み取るためのページフォールトのオーバーヘッドは、単一のread()システムコールを実行するだけの場合に比べて非常に高かった。これは、カーネルが読み取りをタイムスライス内で完全に満足できる場合があるため、コードが切り替わらないためです。ページフォールトが発生すると、別のプログラムがスケジュールされ、ファイル操作の待機時間が長くなる可能性が高くなります。
malloc
は、メモリの一部よりも速く、1 read
をメモリに入れます。これにより、メモリマップを処理するのと同じコードでmalloc'edを処理できます。
read
アクセスのオーバーヘッドが仮想メモリ操作のオーバーヘッドより高くなるように、特定のサイズのマップが必要です。
mmap
、ページテーブルの4つのエントリを更新する必要があります。ただしread
、16Kのバッファにコピーするために使用すると、4ページのテーブルエントリが更新されます。言うまでもなく、16Kをユーザーアドレス空間にコピーする必要があります。それでは、ページテーブルでの操作の違いについて詳しく説明していただけmmap
ますか。
mmap
大きなファイルにランダムにアクセスできる場合に有利です。もう1つの利点は、バッファリングに煩わされることなく、メモリ操作(memcpy、ポインタ演算)でアクセスできることです。バッファーよりも大きな構造体がある場合にバッファーを使用すると、通常のI / Oが非常に困難になることがあります。正しく処理するのが難しいことが多い処理コードは、mmapの方が一般に簡単です。これは、で作業するときに特定の落とし穴があると言いましたmmap
。人々がすでに述べたように、mmap
セットアップにはかなりの費用がかかるため、特定のサイズ(マシンによって異なる)に対してのみ使用する価値があります。
ファイルへの純粋な順次アクセスの場合、適切な呼び出しでmadvise
問題を軽減することもできますが、必ずしも優れたソリューションであるとは限りません。
アーキテクチャ(SPARC、itanium)のアラインメント制限に注意する必要があります。読み取り/書き込みIOを使用すると、バッファーは適切にアラインされ、キャストされたポインターを逆参照するときにトラップしません。
また、マップの外にアクセスしないように注意する必要があります。マップで文字列関数を使用していて、ファイルの末尾に\ 0が含まれていない場合、これは簡単に発生します。最後のページは0で埋められるため、ファイルサイズがページサイズの倍数ではない場合、ほとんどの場合に機能します(マップされた領域は常にページサイズの倍数のサイズです)。
他の素晴らしい答えに加えて、Googleの専門家Robert Loveによって書かれたLinuxシステムプログラミングからの引用:
の利点
mmap( )
経由でファイルを操作する
mmap( )
ことには、標準read( )
およびwrite( )
システムコールに比べていくつかの利点があります。それらの中には:
メモリマップトファイルの読み取りと書き込みにより、
read( )
またはwrite( )
システムコールを使用するときに発生する無関係なコピーが回避されます。潜在的なページフォールトは別として、メモリマップトファイルの読み取りおよび書き込みによって、システムコールやコンテキストスイッチのオーバーヘッドが発生することはありません。メモリへのアクセスと同じくらい簡単です。
複数のプロセスが同じオブジェクトをメモリにマッピングする場合、データはすべてのプロセス間で共有されます。読み取り専用および書き込み可能な共有マッピングは、全体が共有されます。非公開の書き込み可能なマッピングでは、まだCOWされていない(コピーオンライト)ページが共有されます。
マッピングを探すには、簡単なポインタ操作が必要です。
lseek( )
システムコールは必要ありません。これらの理由から、
mmap( )
は多くのアプリケーションにとって賢い選択です。の短所
mmap( )
を使用する場合は、次の点に注意して
mmap( )
ください。
メモリマッピングは常にサイズが整数のページ数です。したがって、バッキングファイルのサイズと整数のページ数の差は、スラックスペースとして「無駄」になります。小さなファイルの場合、マッピングのかなりの部分が無駄になる可能性があります。たとえば、4 KBページの場合、7バイトのマッピングは4,089バイトを浪費します。
メモリマッピングは、プロセスのアドレス空間に収まる必要があります。32ビットのアドレス空間では、非常に多数のさまざまなサイズのマッピングが原因でアドレス空間が断片化し、大きな連続した空き領域を見つけるのが困難になる可能性があります。もちろん、この問題は64ビットのアドレス空間ではそれほど顕著ではありません。
カーネル内のメモリマッピングと関連データ構造の作成と維持にはオーバーヘッドがあります。このオーバーヘッドは、前のセクションで説明した二重コピーを排除することで、特に大きくて頻繁にアクセスされるファイルの場合は、一般に回避されます。
これらの理由により、のメリットは
mmap( )
、マップされたファイルが大きい場合(したがって、無駄なスペースがマッピング全体に占める割合が小さい場合)、またはマップされたファイルの合計サイズがページサイズで割り切れる場合(したがって、無駄なスペースはありません)。
メモリマッピングは、従来のIOに比べて速度が大幅に向上する可能性があります。これにより、オペレーティングシステムは、メモリマップファイルのページがタッチされたときに、ソースファイルからデータを読み取ることができます。これは、OSが検出し、OSがファイルから対応するデータを自動的にロードする障害ページを作成することによって機能します。
これはページングメカニズムと同じように機能し、通常、システムページの境界とサイズ(通常は4K)(ほとんどのファイルシステムキャッシュが最適化されるサイズ)のデータを読み取ることにより、高速I / O向けに最適化されます。
pread
ます。Solaris 9 Sparc(V890)では、プリアドアクセスはmemcpy
mmapからのアクセスよりも2〜3倍遅くなります。しかし、シーケンシャルアクセスは必ずしも高速である必要はありません。
まだリストされていない利点はmmap()
、読み取り専用マッピングをクリーンなページとして維持できることです。プロセスのアドレス空間にバッファを割り当て、read()
ファイルからバッファを埋めるためにを使用すると、そのバッファに対応するメモリページは、書き込まれたためダーティになります。
ダーティページは、カーネルによってRAMから削除できません。スワップ領域がある場合は、ページアウトしてスワップできます。ただし、これにはコストがかかり、フラッシュメモリのみを備えた小さな組み込みデバイスなどの一部のシステムでは、スワップはまったくありません。その場合、バッファはプロセスが終了するか、おそらくでそれを返すまで、RAM内でスタックし続けますmadvise()
。
mmap()
ページに書き込まれていないものはクリーンです。カーネルがRAMを必要とする場合、それらは単にそれらをドロップし、ページがあったRAMを使用できます。マッピングを持つプロセスが再びそれにアクセスすると、カーネルはページフォールトを引き起こし、カーネルは元のファイルからページを再ロードします。そもそも彼らが住むのと同じ方法です。
これは、マップされたファイルを使用する複数のプロセスが利点であることを必要としません。
read()
、データが最終的に配置されるページは、元のファイルとは関係ありません。したがって、スワップスペースを除いて、それらを書き出すことはできません。ファイルの場合はmmap()ed
、マッピングは、(読み取り専用ではなく)書き込み可能である、とに書き込まれ、それはマッピングがあったかどうかに依存しますMAP_SHARED
かMAP_PRIVATE
。共有マッピングはファイルに書き込むことができますが、プライベートマッピングはできません。