메모리 매핑
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