Mmap

컴퓨팅에서 mmap(2) OR 메모리 매칭 파일는 POSIX를 준수하는 유닉스 시스템 호출로, 파일이나 장치를 메모리에 매핑한다. 이는 메모리 맵 파일 I/O 방식이다. 파일 내용이 디스크에서 즉시 읽히지 않고 초기에는 물리적 RAM을 전혀 사용하지 않으므로 요구 페이징을 구현한다. 디스크에서 실제 읽기는 특정 위치에 접근한 후 느긋한 방식으로 수행된다. 매핑이 더 이상 필요하지 않으면 munmap(2)를 사용하여 포인터를 언매핑해야 한다. 예를 들어, 매핑된 영역을 실행 가능으로 표시하는 것과 같은 보호 정보는 mprotect(2)를 사용하여 관리할 수 있으며, madvise(2)를 사용하여 특별한 처리를 적용할 수 있다.

리눅스, macOS 및 BSD에서는 mmap이 여러 유형의 매핑을 생성할 수 있다. 다른 운영체제는 이들 중 일부만 지원할 수 있다. 예를 들어, 전역 VFS 또는 I/O 캐시가 없는 운영체제에서는 공유 매핑이 실용적이지 않을 수 있다.

역사
메모리 맵 파일의 원래 설계는 TOPS-20 운영체제에서 나왔다. mmap 및 관련 시스템 호출은 유닉스 BSD 버전의 일부로 설계되었다. 이들의 API는 4.2BSD 시스템 매뉴얼에 이미 기술되었지만, 해당 릴리스나 4.3BSD에서는 구현되지 않았다. 그러나 썬 마이크로시스템즈는 썬OS 운영체제의 4.0 릴리스에서 이 API를 구현했다. 캘리포니아 대학교 버클리의 BSD 개발자들은 썬에 그 구현을 기부해 달라고 요청했지만 성공하지 못했다. 대신 4.3BSD-Reno는 Mach의 가상 메모리 시스템을 기반으로 한 구현과 함께 출시되었다.

 파일 백업 및 익명 
파일 백업 매핑은 프로세스의 가상 메모리 영역을 파일에 매핑한다. 즉, 해당 메모리 영역을 읽으면 파일이 읽힌다. 이것이 기본 매핑 유형이다.

익명 매핑은 어떤 파일에도 백업되지 않은 프로세스의 가상 메모리 영역을 MAP_ANONYMOUS/MAP_ANON 플래그를 통해 사용할 수 있도록 매핑한다. 내용은 0으로 초기화된다. 이러한 측면에서 익명 매핑은 malloc과 유사하며, 특정 할당, 특히 큰 할당을 위해 일부 malloc 구현에서 사용된다.

 메모리 가시성 
매핑이 공유(MAP_SHARED 플래그가 설정됨)되면, 프로세스가 fork(2) 시스템 호출을 사용하여 포크될 때 보존된다. 따라서 한 프로세스에서 매핑된 영역에 대한 쓰기는 관련된 모든(부모, 자식 또는 형제) 프로세스에서 즉시 볼 수 있다. 매핑이 공유되고 파일로 백업된 경우(MAP_ANONYMOUS가 아님) 기본 파일 매체는 msync(2) 시스템 호출로 전달된 후에만 쓰기가 보장된다. 반면, 매핑이 사적(MAP_PRIVATE 플래그가 설정됨)인 경우 변경 사항은 다른 프로세스에 표시되지 않으며 파일에도 기록되지 않는다.

기본 파일을 읽거나 쓰는 프로세스는 파일을 매핑한 다른 프로세스와 항상 동일한 데이터를 보지는 않는다. 파일의 세그먼트가 RAM으로 복사되고 주기적으로 디스크로 플러시되기 때문이다. msync(2) 호출을 통해 동기화를 강제할 수 있다.

파일에 mmap을 사용하면 동일한 파일에 접근하는 애플리케이션의 메모리 오버헤드를 크게 줄일 수 있다. 각 애플리케이션이 파일에 접근하기 위해 파일을 로드하는 대신, 파일이 포함하는 메모리 영역을 공유할 수 있다. 이는 mmap(2)이 때때로 프로세스 간 통신 (IPC)에 사용된다는 것을 의미한다. 최신 운영체제에서는 mmap(2)이 일반적으로 System V IPC 공유 메모리 기능보다 선호된다.

System V 공유 메모리(shmem)와 메모리 맵 I/O(mmap)의 주요 차이점은 System V 공유 메모리가 영구적이라는 것이다. 프로세스에 의해 명시적으로 제거되지 않는 한, 메모리에 유지되며 시스템이 종료될 때까지 계속 사용할 수 있다. mmap된 메모리는 애플리케이션 실행 간에 영구적이지 않다(파일로 백업되지 않은 경우).

 C 프로그래밍 언어에서의 사용 예시 
#include <sys/types.h>
#include <sys/mman.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/* This example shows how an mmap of /dev/zero is equivalent to
   using anonymous memory (MAP_ANON) not connected to any file.
   N.B. MAP_ANONYMOUS or MAP_ANON are supported by most UNIX
   versions, removing the original purpose of /dev/zero.
*/
/* Does not work on OS X or macOS, where you can't mmap over /dev/zero */
int main(void)
{
        const char str1[] = "string 1";
        const char str2[] = "string 2";
        pid_t parpid = getpid(), childpid;
        int fd = -1;
        char *anon, *zero;

        if ((fd = open("/dev/zero", O_RDWR, 0)) == -1)
                err(1, "open");

        anon = (char*)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
        zero = (char*)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

        if (anon == MAP_FAILED || zero == MAP_FAILED)
                errx(1, "either mmap");

        strcpy(anon, str1);
        strcpy(zero, str1);

        printf("PID %d:\tanonymous %s, zero-backed %s\n", parpid, anon, zero);
        switch ((childpid = fork())) {
        case -1:
                err(1, "fork");
                /* NOTREACHED */
        case 0:
                childpid = getpid();
                printf("PID %d:\tanonymous %s, zero-backed %s\n", childpid, anon, zero);
                sleep(3);

                printf("PID %d:\tanonymous %s, zero-backed %s\n", childpid, anon, zero);
                munmap(anon, 4096);
                munmap(zero, 4096);
                close(fd);
                return EXIT_SUCCESS;
        }

        sleep(2);
        strcpy(anon, str2);
        strcpy(zero, str2);

        printf("PID %d:\tanonymous %s, zero-backed %s\n", parpid, anon, zero);
        munmap(anon, 4096);
        munmap(zero, 4096);
        close(fd);
        return EXIT_SUCCESS;
}

샘플 출력:
<nowiki>
PID 22475:      anonymous string 1, zero-backed string 1
PID 22476:      anonymous string 1, zero-backed string 1
PID 22475:      anonymous string 2, zero-backed string 2
PID 22476:      anonymous string 2, zero-backed string 2
</nowiki>

 데이터베이스 구현에서의 사용 
mmap 시스템 호출은 버퍼 풀 구현의 대안으로 다양한 데이터베이스 구현에서 사용되었지만, 이는 버퍼 풀을 통해서만 현실적으로 해결할 수 있는 다른 문제들을 야기했다.

 같이 보기 
 물리적 메모리보다 더 많은 주소 공간이 있을 때의 가상 메모리
 가상 메모리 구현을 위한 페이징
 mmap에 의해 활용되는 디스크 캐싱 메커니즘을 위한 버퍼 캐시
 mmap에 의해 구현되는 스키마를 위한 요구 페이징

 각주 

 외부 링크 
 POSIX 표준의 설명
 차이점:
 DragonFly BSD
 FreeBSD
 NetBSD
 OpenBSD
 illumos
 Mac OS X
 Solaris
 HP-UX
 QNX
 Windows
 MapViewOfFile win32 함수는 mmap과 다소 동일하다.
 더 많은 예제 소스 코드:
 SharedHashFile, mmap()을 사용하여 구현된 오픈 소스 공유 메모리 해시 테이블.

분류:프로세스 간 통신
분류:C POSIX 라이브러리