メモリにマップされたファイル

この記事では、メモリにマップされたファイル(メモリマップファイル、以降-MMF )などのすばらしいことについてお話したいと思います。

時々、それらを使用すると、通常のバッファリングされたファイル処理と比較して、かなり大きなパフォーマンスの向上が得られます。



これは、メモリ上のファイルを表示できるメカニズムです。 したがって、そこからデータを読み取る場合、対応するバイトがファイルから読み取られます。 記録と同様です。

「もちろん、クールですが、それは何をもたらしますか?」とあなたは尋ねます。 例で説明します。

大きなファイル(数十または数百メガバイト)を処理するタスクに直面しているとします。 タスクは簡単なようです-ファイルを開き、ブロックからメモリにコピーして、処理します。 同時に何が起こりますか? 各ブロックは一時キャッシュにコピーされ、次にそこからメモリにコピーされます。 そして、各ブロックで。 キャッシュ+大量のコピー操作のために、最適ではないメモリ使用量があります。 どうする?

ここで、MMFメカニズムが役立ちます。 ファイルがマップされているメモリにアクセスすると、データがディスクからキャッシュにダウンロードされ(まだ存在しない場合)、キャッシュがプログラムのアドレススペースにマップされます。 このデータが削除されると、表示はキャンセルされます。 したがって、キャッシュからバッファへのコピー操作を取り除きます。 さらに、ディスクでの作業の最適化について心配する必要はありません。OSカーネルがすべてのダーティな作業を処理します。

ある時、私は実験を行いました。 定量化を使用して、バッファリングされた大きな500 mbファイルを別のファイルにコピーするプログラムの速度を測定しました。 そして、同じことをするプログラムの速度ですが、MMFの助けを借りて。 したがって、2番目のものはほぼ30%速く動作します(Solarisでは、他のOSでは結果が異なる場合があります)。 同意する、悪くない。

この機会を利用するために、ファイルをメモリにマップしたいという要望をカーネルに伝える必要があります。 これはmmap()関数を使用して行われます。

#include<sys/mman.h>

void *mmap( void *addr, size_t len, int prot, int flag, int filedes, off_t off);






マップされたメモリの開始アドレス、または失敗した場合はMAP_FAILEDを返します。

最初の引数は、リフレクトされたメモリの一部の先頭の目的のアドレスです。 いつ役立つかわかりません。 0を渡す-カーネル自体がこのアドレスを選択します。

len-メモリにマップされるバイト数。

protは、表示されたメモリ領域のセキュリティの程度(読み取り専用、書き込み専用、実行、領域利用不可)を決定する数値です。 通常の値はPROT_READPROT_WRITEです (ORを介して結合できます)。 私はこれにこだわらない-マナでもっと読んでください。 メモリのセキュリティは、ファイルを開く権利よりも低く設定されないことに注意してください。

flag-領域の属性を説明します。 通常の値はMAP_SHAREDです。 残りはマナを吸う。 ただし、 MAP_FIXEDを使用すると、アプリケーションの移植性が低下することに注意してください。 そのサポートはPOSIXシステムではオプションです。

filedes-ご想像のとおり -表示されるファイル記述子。

off-ファイルの先頭からの表示領域のオフセット。



重要なお知らせ 。 MMFを使用してファイルに書き込む場合は、マッピングする前に、表示されるメモリのサイズ以上の最終ファイルサイズを設定する必要があります。 そうしないと、 SIGBUSに遭遇します。



以下は、MMFを使用してファイルをコピーするプログラムの例です(すばらしい本「Unix。Professional Programming」から盗まれました)。

#include <fcntl.h>

#include <sys/mman.h>

int main( int argc, char *argv[])

{

int fdin, fdout;

void *src, *dst;

struct stat statbuf;

if (argc != 3)

err_quit( ": %s <fromfile> <tofile>" , argv[0]);

if ( (fdin = open(argv[1], O_RDONLY)) < 0 )

err_sys( " %s " , argv[1]);

if ( (fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0 )

err_sys( " %s " , argv[2]);

if ( fstat(fdin, &statbuf) < 0 ) /* */

err_sys( "fstat error" );

/* */

if ( lseek(fdout, statbuf.st_size - 1, SEEK_SET) == -1 )

err_sys( " lseek" );

if ( write(fdout, "" , 1) != 1 )

err_sys( " write" );

if ( (src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0)) == MAP_FAILED )

err_sys( " mmap " );

if ( (dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0)) == MAP_FAILED )

err_sys( " mmap " );

memcpy(dst, src, statbuf.st_size); /* */

exit(0);

}


* This source code was highlighted with Source Code Highlighter .






それだけです。 この記事がお役に立てば幸いです。 私は建設的な批判を喜んで受け入れます。



All Articles