파일 액세스에 언제 mmap을 사용해야합니까?


276

POSIX 환경은 파일에 액세스하는 최소한 두 가지 방법을 제공합니다. 시스템 호출 표준있다 open(), read(), write(), 친구뿐만 아니라, 사용할 수있는 옵션이있다mmap() 가상 메모리에 파일을 매핑 할 수는.

언제 다른 것을 사용하는 것이 바람직합니까? 두 개의 인터페이스를 포함하여 장점이있는 개별 장점은 무엇입니까?


16
또한 Linap Torvalds의 mmap () vs. 읽기 블록그 게시물 을 참조하십시오.
MvG

답변:


299

mmap동일한 파일에서 읽기 전용 방식으로 데이터에 액세스하는 여러 프로세스가있는 경우 좋습니다. 이는 내가 쓰는 서버 시스템 종류에서 일반적입니다. mmap이러한 모든 프로세스가 동일한 실제 메모리 페이지를 공유하여 많은 메모리를 절약 할 수 있습니다.

mmap또한 운영 체제에서 페이징 작업을 최적화 할 수 있습니다. 예를 들어, 두 개의 프로그램을 고려하십시오. 로 생성하는 버퍼로 파일 A을 읽는 프로그램 과 1MB 파일을 메모리로 1MB만드는 malloc프로그램 B. mmaps운영 체제가 A의 메모리 일부를 교체 해야하는 경우 메모리를 재사용하기 전에 교체 할 버퍼의 내용을 써야합니다. 년 B의 경우 어떤 수정되지 않은 mmapOS가 그들이 있던 기존 파일에서 복원하는 방법을 알고 있기 때문에 'D 페이지를 즉시 다시 사용할 수 있습니다 mmap에서'D. (OS는 쓰기 가능한 복사mmap 페이지를 읽기 전용으로 표시하고 쓰기시 복사 와 유사한 세그먼트 오류를 포착 하여 수정되지 않은 페이지를 감지 할 수 있습니다. 전략 ).

mmap프로세스 간 통신 에도 유용합니다 . 할 수 있습니다 mmap필요가 의사 소통을하고 다음에 동기화 기본을 사용하는 과정에서 읽기 / 쓰기로 파일 mmap'd지역 (이것은 무엇 MAP_HASSEMAPHORE플래그입니다).

한 곳에서 mmap당신은 32 비트 컴퓨터에 매우 큰 파일을 작업해야하는 경우 어색 할 수있다. 이는 mmap프로세스의 주소 공간에서 매핑되는 파일의 전체 범위에 맞도록 충분히 큰 연속 주소 블록을 찾아야 하기 때문 입니다. 주소 공간이 조각난 경우 2GB의 여유 공간이있을 수 있지만 개별적인 범위가 1GB 파일 매핑에 맞지 않는 경우 문제가 될 수 있습니다. 이 경우 파일을 원하는 크기보다 작은 청크로 매핑해야 할 수도 있습니다.

mmap읽기 / 쓰기를 대체하는 또 다른 잠재적 어색함 은 페이지 크기의 오프셋에서 매핑을 시작해야한다는 것입니다. 오프셋에서 일부 데이터를 얻으려면 X해당 오프셋을 수정하여 다음과 호환되도록하십시오.mmap .

마지막으로, 읽기 / 쓰기는 일부 유형의 파일로 작업 할 있는 유일한 방법 입니다. 파이프ttysmmap같은 것들에는 사용할 수 없습니다 .


10
늘어나는 파일에 mmap ()을 사용할 수 있습니까? 아니면 mmap () 메모리 / 파일을 할당 할 때 크기가 고정되어 있습니까?
Jonathan Leffler

29
mmap 전화를 걸 때 크기를 지정해야합니다. 따라서 꼬리 작업과 같은 작업을 수행하려면 적합하지 않습니다.
Don Neufeld

5
Afaik MAP_HASSEMAPHORE은 BSD에만 해당됩니다.
Patrick Schlüter

6
@JonathanLeffler 확실히 증가하는 파일에는 mmap ()을 사용할 수 있지만 파일이 처음 할당 한 공간의 한계에 도달하면 새로운 크기로 mmap ()을 다시 호출해야합니다. LevelDB의 PosixMmapFile은 좋은 예입니다. 그러나 1.15에서 mmap 사용을 중단했습니다. Github
baotiao

4
mmap은 파일을 여러 단계로 처리해야하는 경우에도 유용 할 수 있습니다. 가상 메모리 페이지 할당 비용은 한 번만 지불됩니다.
Jib

69

mmap ()이 유리하지 않은 영역 중 하나는 작은 파일을 읽을 때 (16K 미만)였습니다. 전체 파일을 읽는 데 실패한 페이지 오버 헤드는 단일 read () 시스템 호출을 수행하는 것과 비교하여 매우 높습니다. 커널이 때때로 타임 슬라이스에서 읽기를 완전히 만족시킬 수 있기 때문에 코드가 바뀌지 않습니다. 페이지 오류로 인해 다른 프로그램이 예약되어 파일 작업의 대기 시간이 길어질 가능성이 높아졌습니다.


4
+1 확인할 수 있습니다. 작은 파일의 경우 malloc메모리 조각 보다 빠르며 1 read로 만듭니다 . 이것은 malloc'ed 처리하는 메모리 맵을 처리하는 동일한 코드를 가질 수 있습니다.
Patrick Schlüter

35
이것은 당신의 정당성이 옳지 않다고 말했습니다. 스케줄러는 차이와 전혀 관련이 없습니다. 차이점은 페이지 테이블에 대한 쓰기 액세스와 다른 프로세스에서 어떤 메모리 페이지와 해당 액세스 권한을 보유하고 있는지를 보유하는 커널의 글로벌 구조입니다. 이 작업은 매우 비용이 많이들 수 있습니다 (캐시 라인을 무효화 할 수 있으며 TLB를 통과 할 수 있으며 테이블이 전역 적이므로 동시 액세스로부터 보호되어야합니다). read액세스 오버 헤드가 가상 메모리 조작의 오버 헤드보다 높 도록 특정 크기의 맵이 필요합니다 .
Patrick Schlüter

1
@ PatrickSchlüter 좋아, mmap () 시작시 페이지 테이블 수정과 관련된 오버 헤드가 있음을 이해합니다. 16K의 파일을 메모리에 매핑한다고 가정 해 봅시다. 페이지 크기가 4K 인 mmap경우 페이지 테이블에서 4 개의 항목을 업데이트해야합니다. 그러나 read16K의 버퍼에 복사 하는 데 사용 하려면 4 개의 페이지 테이블 항목도 업데이트해야하며 16K를 사용자 추가 공간에 복사해야합니다. 따라서 페이지 테이블에서 작업의 차이점과 비용이 얼마나 비싼 지 자세히 설명 할 수 mmap있습니까?
flow2k

45

mmap큰 파일에 무작위로 액세스 할 때 이점이 있습니다. 또 다른 장점은 버퍼링에 신경 쓰지 않고 메모리 작업 (memcpy, 포인터 산술)으로 액세스한다는 것입니다. 버퍼보다 큰 구조를 가지고있을 때 버퍼를 사용할 때 일반 I / O가 매우 어려울 수 있습니다. 처리하기 어려운 코드는 종종 제대로 이해하기 어렵습니다. mmap은 일반적으로 더 쉽습니다. 이것으로 작업 할 때 특정 함정이 있다고 말했습니다 mmap. 사람들이 이미 언급했듯이 mmap설정하는 데 비용이 많이 들기 때문에 주어진 크기 (기계마다 다름)에만 사용할 가치가 있습니다.

파일에 대한 순차 순차 액세스의 madvise경우 문제를 완화 하기위한 적절한 호출이 항상 더 나은 솔루션 은 아닙니다.

읽기 / 쓰기 IO를 사용하면 아키텍처 (SPARC, 아이테니엄)의 정렬 제한에주의해야합니다. 읽기 / 쓰기 IO를 사용하면 버퍼가 올바르게 정렬되고 캐스트 된 포인터를 역 참조 할 때 트랩되지 않습니다.

또한지도 외부에 액세스하지 않도록주의해야합니다. 맵에서 문자열 함수를 사용하고 파일 끝에 \ 0이 없으면 쉽게 발생할 수 있습니다. 마지막 페이지가 0으로 채워져 파일 크기가 페이지 크기의 배수가 아닌 경우 대부분 작동합니다 (매핑 된 영역은 항상 여러 페이지 크기의 크기 임).


30

다른 좋은 답변 외에도 Google의 전문가 Robert Love가 작성한 Linux 시스템 프로그래밍 의 인용문은 다음과 같습니다.

장점 mmap( )

통해 파일 조작 mmap( ) 하면 표준 read( )write( )시스템 호출 에 비해 몇 가지 장점이 있습니다. 그들 중에는 :

  • 에서 읽기 및 메모리 매핑 된 파일에 기록하면 사용할 때 발생하는 불필요한 복사 방지 read( )또는 write( )데이터와 사용자 영역 버퍼에서 복사해야하는 시스템 호출을.

  • 잠재적 인 페이지 오류 외에도 메모리 매핑 된 파일을 읽고 쓰는 데 시스템 호출이나 컨텍스트 전환 오버 헤드가 발생하지 않습니다. 메모리에 액세스하는 것만 큼 간단합니다.

  • 여러 프로세스가 동일한 객체를 메모리에 매핑하면 모든 프로세스간에 데이터가 공유됩니다. 읽기 전용 및 공유 쓰기 가능 매핑은 전체적으로 공유됩니다. 개인 쓰기 가능 매핑은 아직 COW (Copy-On-Write) 페이지를 공유합니다.

  • 매핑을 탐색하려면 간단한 포인터 조작이 필요합니다. lseek( )시스템 호출이 필요하지 않습니다 .

이러한 이유들로, mmap( ) 많은 응용 프로그램에 현명한 선택입니다.

단점 mmap( )

사용할 때 명심해야 할 몇 가지 사항이 있습니다 mmap( ).

  • 메모리 매핑은 항상 페이지 크기의 정수입니다. 따라서, 백업 파일의 크기와 정수 페이지 수의 차이는 여유 공간으로 "낭비"됩니다. 작은 파일의 경우 상당한 비율의 매핑이 낭비 될 수 있습니다. 예를 들어, 4KB 페이지에서 7 바이트 맵핑은 4,089 바이트를 낭비합니다.

  • 메모리 매핑은 프로세스의 주소 공간에 맞아야합니다. 32 비트 주소 공간을 사용하면 매우 많은 수의 다양한 크기의 매핑으로 주소 공간이 조각화되어 사용 가능한 큰 연속 영역을 찾기가 어려울 수 있습니다. 물론이 문제는 64 비트 주소 공간에서는 훨씬 덜 분명합니다.

  • 커널 내에서 메모리 맵핑 및 연관된 데이터 구조를 작성하고 유지 보수하는 데 오버 헤드가 있습니다. 이 오버 헤드는 일반적으로 이전 섹션에서 언급 한 이중 복사본을 제거하여, 특히 더 크고 자주 액세스하는 파일을 제거함으로써 제거됩니다.

이러한 이유로 인해, mmap( )매핑 된 파일이 크거나 (따라서 낭비되는 공간이 전체 매핑의 작은 비율 인 경우) 또는 매핑 된 파일의 총 크기가 페이지 크기로 균등하게 나올 때 이점 이 가장 크게 실현됩니다 ( 따라서 낭비되는 공간이 없습니다).


13

메모리 매핑은 기존 IO에 비해 속도가 크게 향상 될 수 있습니다. 메모리 맵핑 파일의 페이지가 터치 될 때 운영 체제가 소스 파일에서 데이터를 읽을 수 있습니다. 이는 운영 체제가 감지 한 후 OS가 파일에서 해당 데이터를 자동으로로드하는 오류 페이지를 작성하여 작동합니다.

이는 페이징 메커니즘과 동일한 방식으로 작동하며 일반적으로 대부분의 파일 시스템 캐시에 최적화 된 크기 인 시스템 페이지 경계 및 크기 (일반적으로 4K)의 데이터를 읽음으로써 고속 I / O에 최적화됩니다.


15
mmap ()이 항상 read ()보다 빠르지는 않습니다. 순차적 읽기의 경우 mmap ()은 측정 가능한 이점을 제공하지 않습니다. 이는 경험적이고 이론적 인 증거를 기반으로합니다. 당신이 저를 믿지 않는다면, 당신 만의 테스트를 작성하십시오.
Tim Cooper

1
프로젝트에서 나오는 숫자, 구 데이터베이스에 대한 일종의 텍스트 색인을 제공 할 수 있습니다. 인덱스는 몇 기가 바이트이며 키는 3 진 트리로 유지됩니다. 인덱스는 여전히 읽기 액세스와 병렬로 증가하고 있으며 매핑 된 파트 외부의 액세스는을 통해 이루어집니다 pread. Solaris 9 Sparc (V890)에서 프리 어드 액세스는 memcpymmap 보다 2 ~ 3 배 느립니다 . 그러나 순차 액세스는 필연적으로 더 빠르지 않습니다.
Patrick Schlüter

19
작은 이쑤시개. 페이징 메커니즘처럼 작동하지 않으며 페이징 메커니즘입니다. 파일을 매핑하면 익명 스왑 파일 대신 메모리 영역이 파일에 할당됩니다.
Patrick Schlüter

2

아직 나열되지 않은 장점은 mmap()읽기 전용 매핑을 깨끗한 페이지 로 유지할 수 있다는 것입니다 . 프로세스의 주소 공간에 버퍼를 할당 한 다음 read()파일에서 버퍼를 채우는 데 사용 하는 경우 해당 버퍼에 해당하는 메모리 페이지 는 기록 된 이후 더티 입니다.

커널은 더티 페이지를 RAM에서 삭제할 수 없습니다. 스왑 공간이 있으면 스왑 공간을 페이징하여 스왑 할 수 있습니다. 그러나 이는 비용이 많이 들고 플래시 메모리 만있는 소형 임베디드 장치와 같은 일부 시스템에서는 스왑이 전혀 없습니다. 이 경우 프로세스가 종료 될 때까지 버퍼가 RAM에 갇히거나으로 다시 반환 될 수 madvise()있습니다.

mmap()페이지에 쓰지 않은 것이 깨끗합니다. 커널에 RAM이 필요한 경우 간단히 삭제하고 페이지에 있던 RAM을 사용할 수 있습니다. 매핑이있는 프로세스가 다시 액세스하면 페이지 오류가 발생하여 커널이 원래 가져온 파일에서 페이지를 다시로드합니다 . 처음부터 같은 방식으로 채워졌습니다.

이를 위해서는 매핑 된 파일을 사용하는 프로세스가 두 개 이상 필요하지 않습니다.


커널이 그 내용을 기본 파일에 먼저 써서 '더러운'mmap'd 페이지를 삭제할 수 없습니까?
Jeremy Friesner

2
을 사용할 때 read()데이터가 들어가는 페이지는 원래 가져온 파일과 아무 관련이 없습니다. 따라서 스왑 공간을 제외하고는 쓸 수 없습니다. 파일이 mmap()ed이고 매핑이 쓰기 가능하고 (읽기 전용이 아니라) 쓰기 인 경우 매핑이 MAP_SHARED또는 에 해당하는지 여부에 따라 다릅니다 MAP_PRIVATE. 공유 매핑은 파일에 쓸 수 있어야하지만 개인용으로는 쓸 수 없습니다.
TrentP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.