전체 큰 파일을 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
이러한 페이지에 쓰면 쓰기 중 복사 할당이 발생할 수 있으므로 매핑에는 메모리 예약이 필요합니다. 이것은 물리적 램 + 스왑보다 너무 큰 것을 매핑 할 수 없음을 의미합니다. MAP_SHARED
대신 매핑을 사용해보십시오 . 이것은 매핑에 대한 쓰기가 디스크에 반영된다는 것을 의미합니다. 따라서 커널은 쓰기 저장을 수행하여 항상 메모리를 확보 할 수 있다는 것을 알고 있으므로 제한하지 않습니다.
또한를 사용하여 매핑하고 PROT_WRITE
있지만 계속해서 메모리 매핑에서 읽습니다. 또한로 파일을 열었습니다. O_RDONLY
이 자체가 다른 문제 일 수 있습니다. 와 함께 O_RDWR
사용 하려면 지정해야합니다 .PROT_WRITE
MAP_SHARED
에 관해서는 PROT_WRITE
86 쓰기 전용 매핑을 지원하지 않지만 다른 플랫폼에서 세그먼테이션 폴트 (segfault)을 일으킬 수 있기 때문 만이, 86에 일에 발생합니다. 요청 PROT_READ|PROT_WRITE
-또는 읽기만 필요한 경우 PROT_READ
.
내 시스템 (676MB RAM, 256MB 스왑이있는 VPS)에서 문제를 재현했습니다. 로 변경 MAP_SHARED
하면 EPERM
오류가 발생합니다 (로 연 백업 파일에 쓸 수 없기 때문에 O_RDONLY
). 로 변경 PROT_READ
하고하는 것은 MAP_SHARED
매핑이 성공 할 수 있습니다.
파일의 바이트를 수정해야하는 경우 한 가지 옵션은 쓰려는 파일의 범위 만 비공개로 만드는 것입니다. 즉, 쓰려는 영역으로 munmap
다시 매핑 MAP_PRIVATE
하십시오. 물론 전체 파일 에 쓰려면 8GB의 메모리가 필요합니다.
Alternately, you can write 1
to /proc/sys/vm/overcommit_memory
. This will allow the mapping request to succeed; however, keep in mind that if you actually try to use the full 8GB of COW memory, your program (or some other program!) will be killed by the OOM killer.
You don't have enough virtual memory to handle that mapping.
As an example, I have a machine here with 8G RAM, and ~8G swap (so 16G total virtual memory available).
If I run your code on a VirtualBox snapshot that is ~8G, it works fine:
$ 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
Now, if I drop the swap, I'm left with 8G total memory. (Don't run this on an active server.) And the result is:
$ sudo swapoff -a
$ ./a.out /media/vms/.../snap.vdi
Size: 9820000256
mmap: Cannot allocate memory
So make sure you have enough virtual memory to hold that mapping (even if you only touch a few pages in that file).
Linux (and apparently a few other UNIX systems) have the MAP_NORESERVE
flag for mmap(2), which can be used to explicitly enable swap space overcommitting. This can be useful when you wish to map a file larger than the amount of free memory available on your system.
This is particularly handy when used with MAP_PRIVATE
and only intend to write to a small portion of the memory mapped range, since this would otherwise trigger swap space reservation of the entire file (or cause the system to return ENOMEM
, if system wide overcommitting hasn't been enabled and you exceed the free memory of the system).
The issue to watch out for is that if you do write to a large portion of this memory, the lazy swap space reservation may cause your application to consume all the free RAM and swap on the system, eventually triggering the OOM killer (Linux) or causing your app to receive a SIGSEGV
.
참고URL : https://stackoverflow.com/questions/7222164/mmap-an-entire-large-file
'Programing' 카테고리의 다른 글
socket.io는 어떻게 작동합니까? (0) | 2020.11.21 |
---|---|
첨부 파일이있는 이메일을 보내기위한 Android Intent (0) | 2020.11.21 |
C #에서 C ++ / CLI를 어떻게 호출합니까? (0) | 2020.11.21 |
SOLID 대 YAGNI (0) | 2020.11.21 |
“Apache Harmony를 사용하는 이유”또는“Android에서 Java 8을 사용하는 방법” (0) | 2020.11.21 |