Open Source Web Development Tutorials - Dev Shed
mmap()を利用する高度なファイルI/O
(2009/03/18公開)
マッピングのサイズ変更
Linuxには、マッピングのサイズを拡大/縮小するmremap()システムコールがあります。これはLinux固有の関数です。
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/mman.h>
void * mremap (void *addr, size_t old_size,
size_t new_size, unsigned long flags);
mremap()のコールは、[addr,addr+old_size)領域内のマッピングを拡大あるいは縮小して、新規サイズnew_sizeに変更します。プロセスのアドレス空間の可用性およびフラグの値次第で、カーネルは同時にマッピングを移動できる可能性もあります。
[addr,addr+old_size)のopening は領域がその低アドレスから開始する(および、低アドレスを含む)ことを示し、closingは領域がその高アドレス直前で停止する(したがって、高アドレスを含まない)ことを示します。このような前提を区間表記と呼びます。
フラグのパラメータは、ゼロまたはMREMAP_MAYMOVEです。MREMAP_MAYMOVEは、要求に応じてカーネルがマッピングを移動し、要求されたサイズ変更を実行できることを示します。大型のサイズ変更の場合は、カーネルがマッピングを移動できるときのほうが、成功の公算が高くなります。
mremap()が成功すると、新規にサイズ変更されたメモリマッピングが戻ります。失敗するとMAP_FAILEDが戻り、errnoは以下のいずれかを示します。
EAGAIN
メモリ領域がロックされているので、サイズ変更ができません。
EFAULT
指定された値域内のページに、プロセスのアドレス空間の有効なページではないページがあります。あるいは、指定されたページの再マッピングで問題が発生しました。
EINVAL
引数が無効でした。
ENOMEM
指定された値域を移動せずに拡大することはできません(かつ、MREMAP_MAYMOVEが与えられなかった場合)。あるいは、プロセスのアドレス空間に十分な空きスペースがありません。
glibcなどのライブラリは、mremap()を利用して、効率的なrealloc()を実行することが少なくありません。realloc()は、元はmalloc()によって取得したメモリブロックをサイズ変更するインターフェースです。以下に例を示します。
void * realloc (void *addr, size_t len)
{
size_t old_size = look_up_mapping_size (addr);
void *p;
p = mremap (addr, old_size, len, MREMAP_MAYMOVE);
if (p == MAP_FAILED)
return NULL;
return p;
}
上例は、すべてのmalloc()割り当てが固有の無名マッピングの場合しか成功しません。たとえそうであっても、性能向上の実現に役立つ一例であることに変わりはありません。上記の例では、look_up_mapping_size()関数が書かれていることが前提です。
GNU C libraryも、mmap()とそのファミリを利用して、メモリ割り当てを実行します。これに関しては第8章で詳しく解説します。
Copyright © 2008 Ziff Davis Enterprise, Inc.
Originally appearing in the U.S. Edition of Dev Shed. All Rights Reserved.








