man
ページから、
MAP_ANONYMOUS
The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require
fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The use of MAP_ANONYMOUS in conjunction with
MAP_SHARED is only supported on Linux since kernel 2.4.
MAP_ANONYMOUS
を使用する目的は何ですか?どんな例でもいいでしょう。また、メモリはどこからマップされますか?
man
ページにThe use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4.
と書かれています。MAP_ANONYMOUSでマップされたメモリを他のプロセスと共有するにはどうすればよいですか?
匿名マッピングは、ゼロ化された仮想ファイルとして表すことができます。匿名マッピングは、使用可能なメモリの単純に大きく、ゼロで満たされたブロックです。これらのマッピングはヒープの外にあるため、データセグメントの断片化には寄与しません。
MAP_ANONYMOUS + MAP_PRIVATE:
MAP_ANONYMOUS + MAP_SHARED:
Linuxでは、匿名マッピングを作成する方法が2つあります。
mAP_ANONYMOUSフラグを指定し、fdに-1を渡します
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
exit(EXIT_FAILURE);
/ dev/zeroを開き、この開かれたfdを渡します
fd = open("/dev/zero", O_RDWR);
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
(このメソッドは通常、BSDなどのMAP_ANONYMOUSフラグがないシステムで使用されます)
匿名マッピングの利点:
-仮想アドレス空間の断片化はありません。マッピング解除後、メモリはすぐにシステムに返されます
-割り当てサイズ、権限の点で変更可能であり、通常のマッピングと同じようにアドバイスを受けることもできます
-各割り当ては、グローバルヒープとは別の個別のマッピングです
匿名マッピングの欠点:
-各マッピングのサイズはシステムのページサイズの整数倍であるため、アドレススペースの浪費につながる可能性があります
-マッピングを作成して返すと、事前に割り当てられたヒープからのオーバーヘッドよりもオーバーヘッドが大きくなります
そのようなマッピングを含むプログラムがプロセスをフォークすると、子はマッピングを継承します。次のプログラムは、このような継承を示しています。
#ifdef USE_MAP_ANON
#define _BSD_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
/*Pointer to shared memory region*/
int *addr;
#ifdef USE_MAP_ANON /*Use MAP_ANONYMOUS*/
addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
exit(EXIT_FAILURE);
}
#else /*Map /dev/zero*/
int fd;
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
fprintf(stderr, "open() failed\n");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
exit(EXIT_FAILURE);
}
if (close(fd) == -1) { /*No longer needed*/
fprintf(stderr, "close() failed\n");
exit(EXIT_FAILURE);
}
#endif
*addr = 1; /*Initialize integer in mapped region*/
switch(fork()) { /*Parent and child share mapping*/
case -1:
fprintf(stderr, "fork() failed\n");
exit(EXIT_FAILURE);
case 0: /*Child: increment shared integer and exit*/
printf("Child started, value = %d\n", *addr);
(*addr)++;
if (munmap(addr, sizeof(int)) == -1) {
fprintf(stderr, "munmap()() failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
default: /*Parent: wait for child to terminate*/
if (wait(NULL) == -1) {
fprintf(stderr, "wait() failed\n");
exit(EXIT_FAILURE);
}
printf("In parent, value = %d\n", *addr);
if (munmap(addr, sizeof(int)) == -1) {
fprintf(stderr, "munmap()() failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
出典:
Linuxプログラミングインターフェイス
第49章:メモリマッピング
作成者:マイケルケリスク
Linuxシステムプログラミング(第3版)
第8章:メモリ管理、
著者:ロバートラブ