ファイルをメモリにマップするとmmap()
いい、呼び出しプロセスの仮想アドレス空間メモリにコストをかけます。本当にデータをメモリにコピーしますか、それともデータはまだディスクに存在しますか? mmap()
より速いですread()
か?
4 に答える
関数が実際に行う唯一のことは、mmap
一部のカーネル データ構造と、場合によってはページ テーブルを変更することです。実際には、物理メモリには何も入れません。を呼び出した後mmap
、割り当てられた領域は物理メモリを指していない可能性があります。アクセスすると、ページ フォールトが発生します。この種のページ フォールトは、カーネルによって透過的に処理されます。実際、これはカーネルの主要な役割の 1 つです。
何が起こるかとmmap
いうと、データはディスク上に残り、プロセスがデータを読み取るときにディスクからメモリにコピーされます。また、投機的に物理メモリにコピーすることもできます。プロセスがスワップ アウトされた場合、mmap
リージョン内のページは既に長期ストレージによってバックアップされているため、スワップするために書き込む必要はありません (もちろん、変更していない限り)。
ただし、mmap
は仮想アドレス空間を消費します。これはmalloc
、 および他の同様の機能 (主mmap
に舞台裏で使用される 、またはsbrk
基本的に の特別なバージョンであるmmap
) と同様です。mmap
を使用してファイルを読み取る場合とファイルを読み取る場合の主な違いread
は、領域内の変更されていないページはmmap
全体的なメモリ負荷に寄与せず、使用されていない限り、メモリに関してはほとんど「フリー」であるということです。対照的に、このread
関数で読み取られたファイルは、使用されているかどうか、および変更されているかどうかにかかわらず、常にメモリ不足に寄与します。
最後に、ランダム アクセスやページの再利用など、有利なユース ケースのみmmap
よりも高速です。read
ファイル、特に小さなファイルを直線的にトラバースするread
場合、ページ テーブルを変更する必要がなく、必要なシステム コールが少ないため、通常は高速になります。
mmap
推奨事項として、スキャンする大きなファイルは通常、64 ビット システムで全体を読み取る必要がmmap
あり、仮想メモリがあまり利用できない 32 ビット システムではチャンクで読み取ることができます。
参照: mmap() と読み取りブロック
(James に感謝):ファイル アクセスに mmap を使用する必要があるのはいつですか?も参照してください。
データはまだディスク上に存在します。OS はいくつかの物理メモリを割り当て、そこにファイル データをコピーして、そこにあるファイルの内容にアクセスします (これは、ファイル データにアクセスしようとしたときに発生します)。その物理メモリは、プロセスの仮想アドレス空間にマップされます。OS は、ファイルの長く使用されていない部分のマップを解除でき、必要に応じてそれらをマップし直します。空き物理メモリがほとんどない場合、マップ解除がより積極的になり、パフォーマンスが低下する可能性があります。
ファイルのメモリ マッピング:
単純な「ファイルの読み取り/書き込み」よりも使用する物理メモリと仮想アドレス空間が少なくて済みます。これは、あちこちにファイル バッファがなく (OS、C 標準ライブラリ、およびプログラム内)、それらの間で不要なコピーがないためです。
単純
な「ファイル読み取り/上記の理由と、「ファイル読み取り」システムコールに関係するユーザーモードとカーネルモード間の遷移を回避するためです。残っている唯一の遷移は、現在マップされていない特定のページをマップするものです。それらは、カーネルで処理されるページ フォールト (=CPU 例外) によって開始されます。必要なものがすべてマップされている限り、ファイル データへのアクセス中にユーザー カーネルの遷移は発生しません。
プロセスの「仮想メモリ」は、プロセスが使用できるアドレスの範囲です。メモリ内で何かを利用できるようにするには、アドレスの範囲を予約する必要があるため、mmap()
仮想メモリがいくらか占有されます。
Linux (および他の多くのシステムはおそらく同様のメカニズムを使用します) では、ファイルを読み取るときに、コンテンツは最初にカーネルによって割り当てられたメモリに読み込まれます (Linux では、これは「ページ キャッシュ」です)。を使用する場合よりもmmap()
、このメモリは、そのプロセスのアドレス空間内のアドレスを割り当てることにより、プロセスで使用できるようになります。を使用する場合read()
、プロセスはアドレス (仮想メモリ) と存在する場所 (物理メモリ) の両方を必要とするバッファを割り当て、データはページ キャッシュからそのバッファにコピーされます (より多くの物理メモリが必要です)。
データは、実際にアクセスされたときにのみディスクから読み取られます。mmap()
実際にメモリをアドレス指定する場合、それread()
はバッファへのコピーであるため、read()
呼び出し内です。
したがってmmap()
、特にランダムアクセスの場合、大きなファイルに対してより効率的です。欠点は、ファイルにしか使用できず、ファイルのようなオブジェクト (パイプ、ソケット、デバイス、/proc ファイルなど) には使用できないことと、ページ フォールト中に IO エラーが検出され、処理が難しいことです ( read はエラーを返し、アプリケーションは回復を試みることができます (ほとんどの場合は回復しません)。後者は主に、接続が失われたことが原因で IO 障害が発生する可能性があるネットワーク ファイルシステムに関する懸念事項です。
コピーは、オリジナルが破棄されることを意味するものではありません。
ディスクの内容をメモリにマップするため、もちろんある時点でビットをコピーする必要があります。
これはアドレス空間が必要であることを意味するため、プロセスの仮想アドレス空間の一部を占有します。