mmap은 보통 file이나 kernel이 alloc한 memory를 user space에서 remap해서 VA로 접근하기 위해 사용하지만,
MAP_ANONYMOUS 로 사용할 경우는, addr=0, fd=-1로 설정하게 된다.
어떤 case에서 이러한 mapping을 사용하는지 보자.
우선, MAP_ANONYMOUS로 할당한다고 해도, user application 상에서 이 memory를 read write 하는데는 아무런 문제가 없다는 것을 미리 알아두자.
http://jake.dothome.co.kr/user-virtual-maps-mmap2/
어떠한 파일하고도 연결되지 않고 0으로 초기화된 영역.
fd는 무시되지만 어떤 경우에는 -1이 요구된다.
offset는 0으로 한다.
MAP_SHARED와 같이 사용될 수도 있다. (커널 v2.4)
MAP_ANONYMOUS + MAP_PRIVATE:
- every call creates a distinct mapping
(각 call 마다 별개의 mapping이 생성된다.)
- children inherit parent's mappings
(child process들은 부모의 mapping을 상속 받음)
- childrens' writes on the inherited mapping are catered in copy-on-write manner
(자식 process가 상속받은 mapping영역에 write를 할때, CoW(별개의 영역으로 기존 내용이 복사되고, 수정이 적용됨) 방식으로 동작함.
- the main purpose of using this kind of mapping is to allocate a new zeroized memory
(이러한 종류의 mapping을 사용하는 주 목적은 0으로 초기화된 memory를 할당하기 위해서 임)
- malloc employs anonymous private mappings to serve memory allocation requests larger than MMAP_THRESHOLD bytes.
typically, MMAP_THRESHOLD is 128kB.
(malloc은 MMAP_THRESHOLD(보통 128KB)보다 큰 memory allocation을 하기 위해서, anonymous private mapping을 사용한다.)
MAP_ANONYMOUS + MAP_SHARED:
- each call creates a distinct mapping that doesn't share pages with any other mapping
- children inherit parent's mappings
- no copy-on-write when someone else sharing the mapping writes on the shared mapping
- shared anonymous mappings allow IPC in a manner similar to System V memory segments, but only between related processes
Anonymous mappings can be pictured as a zeroized virtual file. Anonymous mappings are simply large, zero-filled blocks of memory ready for use. These mappings reside outside of the heap, thus do not contribute to data segment fragmentation.
MAP_ANONYMOUS + MAP_PRIVATE:
- every call creates a distinct mapping
- children inherit parent's mappings
- childrens' writes on the inherited mapping are catered in copy-on-write manner
- the main purpose of using this kind of mapping is to allocate a new zeroized memory
- malloc employs anonymous private mappings to serve memory allocation requests larger than MMAP_THRESHOLD bytes.
typically, MMAP_THRESHOLD is 128kB.
MAP_ANONYMOUS + MAP_SHARED:
- each call creates a distinct mapping that doesn't share pages with any other mapping
- children inherit parent's mappings
- no copy-on-write when someone else sharing the mapping writes on the shared mapping
- shared anonymous mappings allow IPC in a manner similar to System V memory segments, but only between related processes
On Linux, there are two ways to create anonymous mappings:
- specify MAP_ANONYMOUS flag and pass -1 for fd
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
exit(EXIT_FAILURE);
- open /dev/zero and pass this opened fd
fd = open("/dev/zero", O_RDWR);
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
(this method is typically used on systems like BSD, that do not have MAP_ANONYMOUS flag)
Advantages of anonymous mappings:
- no virtual address space fragmentation; after unmapping, the memory is immediately returned to the system
VA에 fragmentation이 없다. unmapping후에 memory는 즉시 system에 반환된다.
- they are modifiable in terms of allocation size, permissions and they can also receive advice just like normal mappings
- each allocation is a distinct mapping, separate from global heap
Disadvantages of anonymous mappings:
- size of each mapping is an integer multiple of system's page size, thus it can lead to wastage of address space
- creating and returning mappings incur more overhead than that of from the pre-allocated heap
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); } |
'Programming > Linux_Platform' 카테고리의 다른 글
systemd log를 dmesg와 console에 enable 하는 방법 (0) | 2020.11.23 |
---|---|
taskset : user process 를 특정 cpu에서 동작하도록 하기 (0) | 2020.04.29 |
[systemd-analyze] systemd debugging & analyze method (0) | 2020.01.22 |
SetUID / SetGID Special File Permissions (0) | 2017.11.22 |
The result of getmntent() function (0) | 2017.09.12 |