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


276

POSIX環境では、少なくとも2つの方法でファイルにアクセスできます。標準のシステムコールがありますopen()read()write()、と友人は、しかし、使用するオプションもありますmmap()仮想メモリにファイルをマップするためには。

どちらを使用するのが望ましいですか?2つのインターフェースを含めることのメリットは何ですか?


16
mmap()と読み取りブロック、およびその回答の1つで参照されているLinus Torvaldsによるこの投稿も参照してください。
MvG 2014年

回答:


299

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

mmapまた、オペレーティングシステムがページング操作を最適化できるようにします。たとえば、2つのプログラムを考えてみましょう。で作成したバッファにファイルAを読み込むプログラムと、1MBのファイルをメモリに書き込むプログラムB。オペレーティングシステムがのメモリの一部をスワップアウトする必要がある場合は、メモリを再利用する前に、バッファの内容を書き込んでスワップする必要があります。場合任意の未修正のOSは、彼らがいた既存のファイルからそれらを復元する方法を知っているので、「Dページはすぐに再利用できるから「D。(OSは最初の書き込み可能なマーキングによって変更されないどのページを検出することができます読み取り専用として」Dページを引くとワンセグ障害と同様に、書き込みのコピー戦略を)。 1MBmallocmmapsABmmapmmapmmap

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

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

mmap読み取り/書き込みの代替として考えられるもう1つの問題は、ページサイズのオフセットからマッピングを開始する必要があることです。オフセットでデータを取得するだけの場合はX、そのオフセットを修正して、と互換性があるようにする必要がありますmmap

そして最後に、読み取り/書き込みは、いくつかのタイプのファイルを操作できる唯一の方法です。 pipesttysmmapなどには使用できません。


10
成長しているファイルでmmap()を使用できますか?または、mmap()メモリ/ファイルを割り当てる時点でサイズが固定されていますか?
ジョナサンレフラー

29
mmap呼び出しを行うときは、サイズを指定する必要があります。したがって、テール操作などを実行する場合は、あまり適していません。
Don Neufeld、

5
Afaik MAP_HASSEMAPHOREはBSDに固有です。
PatrickSchlüter、2010年

6
@JonathanLeffler確かに、増大するファイルに対してmmap()を使用できますが、ファイルが最初に割り当てたスペースの制限に達したときは、新しいサイズでmmap()を再度呼び出す必要があります。LevelDBのPosixMmapFileが良い例です。しかし、1.15からmmapの使用を中止しました。古いバージョンはGithub
baotiao

4
mmapは、ファイルを複数のパスで処理する必要がある場合にも役立ちます。仮想メモリページを割り当てるコストは、一度だけ支払われます。
ジブ

69

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


4
+1確認できます。小さなファイルの場合mallocは、メモリの一部よりも速く、1 readをメモリに入れます。これにより、メモリマップを処理するのと同じコードでmalloc'edを処理できます。
PatrickSchlüter、2010年

35
これは言った、それのためのあなたの正当化は正しくありません。スケジューラーは違いとは何の関係もありません。違いは、ページテーブルへの書き込みアクセスです。これは、どのプロセスがどのメモリページとそのアクセス権を保持しているかを保持するカーネルのグローバル構造です。この操作は非常にコストがかかる可能性があります(キャッシュラインが無効になる可能性があります。TLBがなくなる可能性があります。テーブルはグローバルなので、同時アクセスから保護する必要があります)。readアクセスのオーバーヘッドが仮想メモリ操作のオーバーヘッドより高くなるように、特定のサイズのマップが必要です。
パトリックSchlüter

1
@PatrickSchlüterわかりました。mmap()の開始時に、ページテーブルの変更を伴うオーバーヘッドがあることを理解しています。16Kのファイルをメモリにマップするとします。4Kのページサイズの場合mmap、ページテーブルの4つのエントリを更新する必要があります。ただしread、16Kのバッファにコピーするために使用すると、4ページのテーブルエントリが更新されます。言うまでもなく、16Kをユーザーアドレス空間にコピーする必要があります。それでは、ページテーブルでの操作の違いについて詳しく説明していただけmmapますか。
flow2k 2018

45

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

ファイルへの純粋な順次アクセスの場合、適切な呼び出しでmadvise問題を軽減することもできますが、必ずしも優れたソリューションであるとは限りません。

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

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


30

他の素晴らしい答えに加えて、Googleの専門家Robert Loveによって書かれたLinuxシステムプログラミングからの引用:

の利点 mmap( )

経由でファイルを操作するmmap( )ことには、標準read( )およびwrite( )システムコールに比べていくつかの利点があります。それらの中には:

  • メモリマップトファイルの読み取りと書き込みにより、read( )またはwrite( )システムコールを使用するときに発生する無関係なコピーが回避されます。

  • 潜在的なページフォールトは別として、メモリマップトファイルの読み取りおよび書き込みによって、システムコールやコンテキストスイッチのオーバーヘッドが発生することはありません。メモリへのアクセスと同じくらい簡単です。

  • 複数のプロセスが同じオブジェクトをメモリにマッピングする場合、データはすべてのプロセス間で共有されます。読み取り専用および書き込み可能な共有マッピングは、全体が共有されます。非公開の書き込み可能なマッピングでは、まだCOWされていない(コピーオンライト)ページが共有されます。

  • マッピングを探すには、簡単なポインタ操作が必要です。lseek( )システムコールは必要ありません。

これらの理由から、mmap( )は多くのアプリケーションにとって賢い選択です。

の短所 mmap( )

を使用する場合は、次の点に注意してmmap( )ください。

  • メモリマッピングは常にサイズが整数のページ数です。したがって、バッキングファイルのサイズと整数のページ数の差は、スラックスペースとして「無駄」になります。小さなファイルの場合、マッピングのかなりの部分が無駄になる可能性があります。たとえば、4 KBページの場合、7バイトのマッピングは4,089バイトを浪費します。

  • メモリマッピングは、プロセスのアドレス空間に収まる必要があります。32ビットのアドレス空間では、非常に多数のさまざまなサイズのマッピングが原因でアドレス空間が断片化し、大きな連続した空き領域を見つけるのが困難になる可能性があります。もちろん、この問題は64ビットのアドレス空間ではそれほど顕著ではありません。

  • カーネル内のメモリマッピングと関連データ構造の作成と維持にはオーバーヘッドがあります。このオーバーヘッドは、前のセクションで説明した二重コピーを排除することで、特に大きくて頻繁にアクセスされるファイルの場合は、一般に回避されます。

これらの理由により、のメリットはmmap( )、マップされたファイルが大きい場合(したがって、無駄なスペースがマッピング全体に占める割合が小さい場合)、またはマップされたファイルの合計サイズがページサイズで割り切れる場合(したがって、無駄なスペースはありません)。


13

メモリマッピングは、従来のIOに比べて速度が大幅に向上する可能性があります。これにより、オペレーティングシステムは、メモリマップファイルのページがタッチされたときに、ソースファイルからデータを読み取ることができます。これは、OSが検出し、OSがファイルから対応するデータを自動的にロードする障害ページを作成することによって機能します。

これはページングメカニズムと同じように機能し、通常、システムページの境界とサイズ(通常は4K)(ほとんどのファイルシステムキャッシュが最適化されるサイズ)のデータを読み取ることにより、高速I / O向けに最適化されます。


15
mmap()が常にread()より高速であるとは限らないことに注意してください。順次読み取りの場合、mmap()を使用しても測定可能な利点はありません。これは経験的および理論的な証拠に基づいています。私を信じないなら、あなた自身のテストを書いてください。
Tim Cooper、

1
私たちのプロジェクトからの数字を与えることができます。これは、フレーズデータベースのテキストインデックスの一種です。インデックスは数ギガバイトの大きさで、キーは三分木で保持されます。インデックスは引き続き読み取りアクセスと並行して増加し、マップされたパーツの外部へのアクセスはを介して行われpreadます。Solaris 9 Sparc(V890)では、プリアドアクセスはmemcpymmapからのアクセスよりも2〜3倍遅くなります。しかし、シーケンシャルアクセスは必ずしも高速である必要はありません。
PatrickSchlüter、2010年

19
ほんの少しのちょっとしたひねり。これはページングメカニズムとは異なり、ページングメカニズムです。ファイルをマッピングすると、匿名スワップファイルではなく、ファイルにメモリ領域が割り当てられます。
PatrickSchlüter、2010年

2

まだリストされていない利点はmmap()、読み取り専用マッピングをクリーンなページとして維持できることです。プロセスのアドレス空間にバッファを割り当て、read()ファイルからバッファを埋めるためにを使用すると、そのバッファに対応するメモリページは、書き込まれたためダーティになります。

ダーティページは、カーネルによってRAMから削除できません。スワップ領域がある場合は、ページアウトしてスワップできます。ただし、これにはコストがかかり、フラッシュメモリのみを備えた小さな組み込みデバイスなどの一部のシステムでは、スワップはまったくありません。その場合、バッファはプロセスが終了するか、おそらくでそれを返すまで、RAM内でスタックし続けますmadvise()

mmap()ページに書き込まれていないものはクリーンです。カーネルがRAMを必要とする場合、それらは単にそれらをドロップし、ページがあったRAMを使用できます。マッピングを持つプロセスが再びそれにアクセスすると、カーネルはページフォールトを引き起こし、カーネルは元のファイルからページを再ロードします。そもそも彼らが住むのと同じ方法です。

これは、マップされたファイルを使用する複数のプロセスが利点であることを必要としません。


カーネルは、最初にその内容を基礎となるファイルに書き出すことによって、「ダーティ」なmmapされたページをドロップできませんか?
Jeremy Friesner

2
を使用する場合read()、データが最終的に配置されるページは、元のファイルとは関係ありません。したがって、スワップスペースを除いて、それらを書き出すことはできません。ファイルの場合はmmap()ed、マッピングは、(読み取り専用ではなく)書き込み可能である、とに書き込まれ、それはマッピングがあったかどうかに依存しますMAP_SHAREDMAP_PRIVATE。共有マッピングはファイルに書き込むことができますが、プライベートマッピングはできません。
TrentP
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.