2016-05-11 19 views
2

アドレス空間がファイルをカバーできると仮定すると、mmapは読み込みようとするファイルの大きさのメモリを単に割り当て、対応するブロック間に1対1の関係を作成します。しかし、そうすることでファイルの読み込み速度が向上するのはなぜですか?実際にファイルの内容を取得するには、ディスクに移動してその上のすべてのバイトを読み取る必要があります。mmapはファイルの読み込み速度をどのように改善しますか?

同じサイズのメモリをmallocすると、ファイル全体を手動でmalloc'ed領域に読み込むのと比べて、どのような違いがありますか?

+0

それは* *読んでスピードアップしません。同じ量のブロックをディスクから読み込む必要があります。プログラマの観点からすると(時には)より便利になります。そして、mmapはメモリの塊を割り当てず、*アドレス空間*を割り当て、実際のデータは*参照された後に*フォールトされます。 – wildplasser

答えて

0

これはありません。具体的には、mmap()は、ファイルを呼び出すときにファイル全体をメモリに読み込まず、何らかのアクセスを高速化しようとします。むしろ、それはファイルをマップします。つまり、ファイルの索引(私は「ゆるやかに」という用語を使用します)はメモリー内に作成され、その「キー」に読み書きしようとするとページフォールトがトリガーされます"つまり、ファイルへの単純なインターフェイスと、ファイルの内容の遅延読み込みの一種があることです。

私は続けることができますが、他の人はそれをよくします。たとえば、hereを参照してください。

+0

レイジーロードでは、メモリマップの速度が遅くなるようですね。今では、ページにアクセスするたびに大量のページを一度に読み取るのと比べて、ディスクを回転させてブロックを読み取る必要があります。それは...ですか? – OneZero

4

mmapの動作が異なります。これは予期しており、プログラムのアクセスパターンに適応しています。また、特定のポリシーをmadviseで設定して、さらに細かく調整することもできます。デマンドページング環境でどのようにmmap作品のはるかに徹底的な議論については

、ここに私の答えを参照してください。Which segments are affected by a copy-on-write?それはまたmmap

mmapの使用について話すようにexecveらを経由して、プログラムの実行の生命線です。 al。だから、それは速いと賭けることができます。助言として、mallocが実際に匿名を使用していることは皮肉なことですmmap

しかし、ここでの議論のために、特に、mmapmallocread(2)

をやっmmap対を持つファイルは、「バッキングストア」(すなわちページング・ディスク)を注意し、メモリ領域のバッキングストアがありますファイルそのもの。このエリアは、ページをカーネルのファイルシステムのバッファページに直接マップします[彼らは長い間統一されています]。したがって、read(2)の場合のように、カーネルファイルシステムのバッファページからアプリケーションページへの無駄なコピーは必要ありません。

malloc/readを実行すると、上記のページが残りますが、malloc'ed領域にページング/スワップディスクのバッキングストアが追加されました。したがって、の場合と同じように、が2回、と同じページバッファを使用します。私が言及したように、データが読み取られたときにその領域にコピーされなければならない。

また、大量の読み込みを実行すると、パフォーマンスが最適ではありません。推奨サイズは、チャンク[ファイルシステムに依存]で約64KBです。

大きな読み込みを実行すると、プログラムは完了するまで開始できません。ファイルのサイズが物理メモリより大きい場合、システムはmalloc領域を読み込み、ページングディスクの前のページをフラッシュすることを無駄に開始し、ファイル全体が完全になるまでファイルの終わり近くのスペースを確保します読み込みます。

つまり、この大きな先読みが発生している間、アプリケーションは[何もしません]と待機しています。 60GBのファイルの場合、起動時間はであり、目立つのはです。

ファイルがの場合は、実際にはと十分な大きさであれば、ページングディスクの空き容量がなくなる(つまり、NULLが返されるmalloc)。

mmapの場合、このような問題はありません。ファイルをマップするときに、すぐにを使用して開始することができます。それは、エリアのバッキングストアから要求に応じて「フォールトイン」します(ファイルシステム内のファイルです)。そして、もしあなたが1 TBのファイルを持っていれば、mmapはそれをうまく処理します。

また、madvise(2)posix_madvise(2)を使用してページ単位で、またはファイル全体を含む任意のページ範囲でマッピングポリシーを制御できます。 madvise syscallは比較的軽量ですので、たくさん使っても問題ありません。これはヒントですが、アプリケーションを遅らせるI/Oは行いません。 I/Oがヒントのために先読みされ始めると、バックグラウンドアクティビティとしてカーネルによって実行されます。

システムに、特定のページがすぐに必要になることを伝えることさえできます[システムはこれをプリフェッチするヒントとしてこれを使用します]。または、ページがもはや必要でないことをシステムに伝えることができます[システムはページバッファメモリ]。

ファイル全体に対して「順次アクセス」のようなことを言うことができます。これは、システムが先読みを自動的に行うことを知っていることと、もはや不要になったページのリリースを知ることを意味しますを実行すると、特定のカーネルFSページバッファが不要になったことをシステムに伝える方法がありません。物理的なRAMがいっぱいになるまで[または一定の制限を超えて]メモリシステム全体に圧力が加わります。

実際には、readを使用して、アプリケーションがファイルの別の部分または別のファイルに移動した後、FSバッファに使用されるメモリの使用量が長く続くことがわかりました。実際、I/O集約型のアプリケーションでは、無関係な[アイドル]プロセスがページを盗み出してページングディスクに流すようにするために、非常に多くのバッファを使います。 I/Oアプリケーションを停止すると、firefoxが自分自身をページングして再び反応するようになるまでに数分かかりました。

私は定期的な読み取りとmmapのためのいくつかの広範なベンチマークを行いました。それらから、mmapは特定のアプリケーションの速度を向上させることができます。

ここに私の答えを参照してください:私はこれをしなかったread line by line in the most efficient way *platform specific*

前に、私は、mmapの給付の懐疑的だったが、ベンチマークはmmapのが勝者であることを示しています。

read(2)(速度用)とfgetsを実行している場合は、ある行が読み取りバッファの境界(つまり、最後の50文字バッファは80文字の行の最初の50バイトを持つ)。そこに上記に投稿するにはあまりにも大きかった私のベンチマークプログラムと結果の以降のバージョンにペーストビンへの別のリンクがSOベンチマークという答えであり、様々なmadviseオプション

を比較することは、このリンク先のページ内のコメントで

注意、

+0

mmapはなぜより速いのですか? mmapはブロックごとに1つずつ到達する必要があると思われますが、他のストリーミング関数は一度に大量のデータを取得します。 mmapはディスクの回転と読み取りを行うだけの時間がかかります。 – OneZero

+0

@OneZero前回の私の回答([忘れてしまった])への新しいリンクを追加しました。また、実際に 'mmap'がどのように動作するのかについて、私の答えに_lot_の説明を追加しました。それはあなたが信じるようには機能しません。それはかなり洗練されています。また、私は 'malloc/read'アプローチとの比較を追加しました。これは、実際には、人々がそれを考えると思われるよりも最適ではありません。 –

+0

すごく良い答え。 –

1

私はこのことに興味がありましたので、ベンチマーキング全体ファイルのファイルサイズは1,1,2,4,8などとなりました。1つはmmap(M)で1回、read(R)で1回(理論的にはfstat-edサイズの呼び出しですが、その呼び出しが部分的な結果を返した場合は再試行します)。読み込み/ mmaping後、各mmaped/readページのバイトは、最適化不可能な方法でアクセスされました。

は、ここに私の結果です:

Size M(µs) R(µs) 
1  9.5  4.2 
2  10.8 4.5 
4  8.4  3.8 
8  8.6  3.8 
16  7.3  4 
32  7.8  3.5 
64  8.3  3.9 
128 9.2  4.6 
256 8.6  4.7 
512 10.6 5.1 
1.0Ki 9.8  4.7 
2.0Ki 10.1 5.4 
4.0Ki 10.5 5.6 
8.0Ki 10.4 6.9 
16Ki 9.9  10 
32Ki 14.4 12.8 
64Ki 16.1 23.7 
128Ki 28.1 41.1 
256Ki 34.5 82.4 
512Ki 57.9 154.6 
1.0Mi 103.5 325.8 
2.0Mi 188.5 919.8 
4.0Mi 396.3 1963.2 
8.0Mi 798.8 3885 
16Mi 1611.4 7660.2 
32Mi 3207.4 23040.2 
64Mi 6712.1 84491.9 

read16Kiまでの約2倍の高速で表示されます。それ以来、mmapは大きな時間を獲得し始めます(64MiBファイルの場合、のファクタ)。

(私のラップトップ上で3.19とLinux上でテストされ、^ 4〜10を繰り返し、同じファイルに読み取ります。)

関連する問題