메모리 매핑

mmap () 시스템 호출은 파일 또는 장치를 메모리에 매핑하는 호출 프로세스의 가상 주소 공간에 매핑을 제공합니다. 이것은 두 가지 유형입니다-

File mapping or File-backed mapping−이 매핑은 프로세스의 가상 메모리 영역을 파일에 매핑합니다. 이는 해당 메모리 영역을 읽거나 쓰면 파일을 읽거나 쓰게됨을 의미합니다. 이것이 기본 매핑 유형입니다.

Anonymous mapping−이 매핑은 파일의 지원없이 프로세스의 가상 메모리 영역을 매핑합니다. 내용은 0으로 초기화됩니다. 이 매핑은 동적 메모리 할당 (malloc ())과 유사하며 특정 할당을 위해 일부 malloc () 구현에서 사용됩니다.

한 프로세스 매핑의 메모리는 다른 프로세스의 매핑과 공유 될 수 있습니다. 이것은 두 가지 방법으로 수행 할 수 있습니다.

  • 두 프로세스가 파일의 동일한 영역을 매핑하면 동일한 물리적 메모리 페이지를 공유합니다.

  • 자식 프로세스가 생성되면 부모의 매핑을 상속하고 이러한 매핑은 부모의 것과 동일한 물리적 메모리 페이지를 참조합니다. 하위 프로세스에서 데이터가 변경되면 하위 프로세스에 대해 다른 페이지가 생성됩니다.

둘 이상의 프로세스가 동일한 페이지를 공유하는 경우 각 프로세스는 매핑 유형에 따라 다른 프로세스에서 만든 페이지 내용의 변경 사항을 볼 수 있습니다. 매핑 유형은 개인 또는 공유 일 수 있습니다.

Private Mapping (MAP_PRIVATE) −이 매핑의 내용에 대한 수정 사항은 다른 프로세스에서 볼 수 없으며 매핑은 기본 파일로 전달되지 않습니다.

Shared Mapping (MAP_SHARED) −이 매핑의 내용에 대한 수정 사항은 다른 프로세스에서 볼 수 있으며 매핑은 기본 파일로 전달됩니다.

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

위의 시스템 호출은 성공시 매핑의 시작 주소를 반환하고 오류시 MAP_FAILED를 반환합니다.

가상 주소 주소는 사용자가 지정하거나 커널에 의해 생성 될 수 있습니다 (addr를 NULL로 전달하면). 표시된 필드 길이에는 매핑 크기 (바이트)가 필요합니다. prot 필드는 PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC와 같은 메모리 보호 값을 각각 액세스, 읽기, 쓰기 또는 실행할 수없는 영역을 나타냅니다. 이 값은 단일 (PROT_NONE)이거나 세 개의 플래그 (마지막 3 개) 중 하나와 OR로 연결될 수 있습니다. 필드 플래그는 매핑 유형 또는 MAP_PRIVATE 또는 MAP_SHARED를 나타냅니다. 필드 'fd'는 매핑 할 파일을 식별하는 파일 설명자를 나타내고 'offset'필드는 파일의 시작점을 의미합니다. 전체 파일을 매핑해야하는 경우 오프셋은 0이어야합니다.

#include <sys/mman.h>

int munmap(void *addr, size_t length);

위의 시스템 호출은 성공시 0을, 오류시 -1을 반환합니다.

시스템 호출 munmap은 이미 메모리 매핑 된 영역의 매핑 해제를 수행합니다. addr 필드는 매핑의 시작 주소를 나타내고 길이는 매핑 해제 할 매핑의 크기 (바이트)를 나타냅니다. 일반적으로 매핑 및 매핑 해제는 매핑 된 전체 영역에 대한 것입니다. 이것이 달라야한다면 축소하거나 두 부분으로 잘라야합니다. addr에 매핑이없는 경우이 호출은 효과가 없으며 호출은 0 (성공)을 반환합니다.

예를 들어 보겠습니다.

Step 1 − 아래와 같이 파일에 영숫자 문자 쓰기 −

0 1 2 25 26 27 28 29 30 31 32 33 34 35 36 37 38 59 60 61
A B C Z 0 1 2 3 4 5 6 7 8 9 A b c x y z

Step 2− mmap () 시스템 호출을 사용하여 파일 내용을 메모리에 매핑합니다. 이것은 메모리에 매핑 된 후 시작 주소를 반환합니다.

Step 3− 값 비싼 read () 시스템 호출을 읽지 않으므로 배열 표기법 (포인터 표기법으로도 액세스 가능)을 사용하여 파일 내용에 액세스합니다. 메모리 매핑을 사용하여 사용자 공간, 커널 공간 버퍼 및 버퍼 캐시 간의 다중 복사를 피하십시오.

Step 4 − 사용자가 "-1"(액세스 종료를 의미)을 입력 할 때까지 파일 내용 읽기를 반복합니다.

Step 5 − 정리 작업을 수행합니다. 즉, 매핑 된 메모리 영역 (munmap ()) 매핑 해제, 파일 닫기 및 파일 제거.

/* Filename: mmap_test.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
void write_mmap_sample_data();

int main() {
   struct stat mmapstat;
   char *data;
   int minbyteindex;
   int maxbyteindex;
   int offset;
   int fd;
   int unmapstatus;
   write_mmap_sample_data();
   if (stat("MMAP_DATA.txt", &mmapstat) == -1) {
      perror("stat failure");
      return 1;
   }
   
   if ((fd = open("MMAP_DATA.txt", O_RDONLY)) == -1) {
      perror("open failure");
      return 1;
   }
   data = mmap((caddr_t)0, mmapstat.st_size, PROT_READ, MAP_SHARED, fd, 0);
   
   if (data == (caddr_t)(-1)) {
      perror("mmap failure");
      return 1;
   }
   minbyteindex = 0;
   maxbyteindex = mmapstat.st_size - 1;
   
   do {
      printf("Enter -1 to quit or ");
      printf("enter a number between %d and %d: ", minbyteindex, maxbyteindex);
      scanf("%d",&offset);
      if ( (offset >= 0) && (offset <= maxbyteindex) )
      printf("Received char at %d is %c\n", offset, data[offset]);
      else if (offset != -1)
      printf("Received invalid index %d\n", offset);
   } while (offset != -1);
   unmapstatus = munmap(data, mmapstat.st_size);
   
   if (unmapstatus == -1) {
      perror("munmap failure");
      return 1;
   }
   close(fd);
   system("rm -f MMAP_DATA.txt");
   return 0;
}

void write_mmap_sample_data() {
   int fd;
   char ch;
   struct stat textfilestat;
   fd = open("MMAP_DATA.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666);
   if (fd == -1) {
      perror("File open error ");
      return;
   }
   // Write A to Z
   ch = 'A';
   
   while (ch <= 'Z') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   // Write 0 to 9
   ch = '0';
   
   while (ch <= '9') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   // Write a to z
   ch = 'a';
   
   while (ch <= 'z') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   close(fd);
   return;
}

산출

Enter -1 to quit or enter a number between 0 and 61: 3 
Received char at 3 is D 
Enter -1 to quit or enter a number between 0 and 61: 28
Received char at 28 is 2 
Enter -1 to quit or enter a number between 0 and 61: 38 
Received char at 38 is c 
Enter -1 to quit or enter a number between 0 and 61: 59 
Received char at 59 is x 
Enter -1 to quit or enter a number between 0 and 61: 65 
Received invalid index 65 
Enter -1 to quit or enter a number between 0 and 61: -99 
Received invalid index -99 
Enter -1 to quit or enter a number between 0 and 61: -1