programing

큰 파일 전체 Mmap()

goodcopy 2022. 7. 27. 22:30
반응형

큰 파일 전체 Mmap()

다음 코드(test.c)를 사용하여 바이너리 파일(~ 8Gb)을 "mmap"하려고 합니다.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define handle_error(msg) \
  do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[])
{
   const char *memblock;
   int fd;
   struct stat sb;

   fd = open(argv[1], O_RDONLY);
   fstat(fd, &sb);
   printf("Size: %lu\n", (uint64_t)sb.st_size);

   memblock = mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0);
   if (memblock == MAP_FAILED) handle_error("mmap");

   for(uint64_t i = 0; i < 10; i++)
   {
     printf("[%lu]=%X ", i, memblock[i]);
   }
   printf("\n");
   return 0;
}

test.c는 다음 명령어를 사용하여 컴파일됩니다.gcc -std=c99 test.c -o test그리고.file테스트 결과:test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

작은 파일에서는 정상적으로 동작하지만 큰 파일을 로드하려고 하면 세그멘테이션 장애가 발생합니다.프로그램은 실제로 다음을 반환합니다.

Size: 8274324021 
mmap: Cannot allocate memory

boost::iostreams::mapped_file을 사용하여 파일 전체를 매핑할 수 있었지만 C와 시스템콜을 사용하여 매핑하고 싶습니다.내 코드에 무슨 문제가 있나요?

MAP_PRIVATE매핑에는 메모리 예약이 필요합니다.이러한 페이지에 기입하면, 카피 온 라이트 할당이 발생하는 일이 있습니다.즉, 물리 RAM + 스왑보다 더 큰 것을 매핑할 수 없습니다.를 사용해 보세요.MAP_SHARED대신 매핑합니다.이는 매핑에 대한 쓰기가 디스크에 반영된다는 것을 의미합니다.따라서 커널은 라이트백을 통해 항상 메모리를 해방할 수 있기 때문에 제한은 없습니다.

또, 이 맵핑에 대해서PROT_WRITE단, 메모리 매핑에서 읽습니다.또한 파일을 열었습니다.O_RDONLY- 이 자체도 문제가 될 수 있습니다.O_RDWR사용하고 싶다면PROT_WRITE와 함께MAP_SHARED.

에 대해서는PROT_WRITEx86은 쓰기 전용 매핑을 지원하지 않지만 다른 플랫폼에서 seg fault를 일으킬 수 있기 때문에 x86에서만 이 문제가 발생합니다.부탁한다PROT_READ|PROT_WRITE- 또는 읽기만 필요한 경우,PROT_READ.

시스템(676MB RAM 탑재 VPS, 256MB 스왑)에서 문제를 재현했습니다.MAP_SHARED결과적으로EPERMerror(로 열린 백업 파일에 쓸 수 없기 때문에)O_RDONLY) 로의 변경PROT_READ그리고.MAP_SHARED그럼 매핑이 성공합니다.

파일의 바이트를 수정해야 하는 경우, 쓸 파일의 범위만 비공개로 하는 방법도 있습니다.그것은,munmap으로 리매핑합니다.MAP_PRIVATE쓰려는 영역을 지정합니다.물론 파일 전체에 쓰려면 8GB의 메모리가 필요합니다.

또는 다음과 같이 쓸 수 있습니다.1이렇게 하면 매핑 요청이 성공할 수 있지만 실제로 8GB의 COW 메모리를 모두 사용하려고 하면 프로그램(또는 다른 프로그램!)이 OOM 킬러에 의해 중지됩니다.

Linux(및 기타 몇몇 UNIX 시스템)에는MAP_NORESERVEmmap(2)의 플래그를 지정합니다.이 플래그는 스왑 영역의 오버커밋을 명시적으로 유효하게 하기 위해서 사용할 수 있습니다.이 기능은 시스템에서 사용 가능한 메모리 용량보다 큰 파일을 매핑할 때 유용합니다.

기능은 특히 이능은 this this this this this this this this this this this this this 와 함께 사용하면 편리합니다.MAP_PRIVATE작은 에만 쓰려고 이 "Swap space reservation"을 반환하게 됩니다.그렇지 않으면 파일 전체의 스왑 공간 예약이 트리거되거나 시스템이 반환됩니다.ENOMEM시스템 전체의 오버 커밋이 유효하게 되어 있지 않고, 시스템의 빈 메모리를 초과하는 경우).

해야 할 에 쓸 빈 킬러(Linux될 수 입니다. 시스템 상에서 스왑하여 최종적으로 OOM Killer(Linux)를 트리거하거나 응용 프로그램이 수신할 수 있다는 것입니다.SIGSEGV.

가상 메모리가 부족하여 매핑을 처리할 수 없습니다.

예를 들어 8G RAM과 최대 8G 스왑(총 16G 가상 메모리 사용 가능)을 갖춘 머신이 있습니다.

최대 8G의 Virtual Box 스냅샷에서 코드를 실행하면 정상적으로 작동합니다.

$ ls -lh /media/vms/.../snap.vdi
-rw------- 1 me users 9.2G Aug  6 16:02 /media/vms/.../snap.vdi
$ ./a.out /media/vms/.../snap.vdi
Size: 9820000256 
[0]=3C [1]=3C [2]=3C [3]=20 [4]=4F [5]=72 [6]=61 [7]=63 [8]=6C [9]=65 

스왑을 해제하면 8G의 총 메모리가 남습니다.(액티브 서버에서 실행하지 마십시오.)결과는 다음과 같습니다.

$ sudo swapoff -a
$ ./a.out /media/vms/.../snap.vdi
Size: 9820000256 
mmap: Cannot allocate memory

따라서 매핑을 저장하기에 충분한 가상 메모리가 있는지 확인하십시오(파일의 몇 페이지만 터치해도 상관없습니다).

언급URL : https://stackoverflow.com/questions/7222164/mmap-an-entire-large-file

반응형