답변:
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 .
마지막으로, 읽기 / 쓰기는 일부 유형의 파일로 작업 할 수 있는 유일한 방법 입니다. 파이프 및 ttys 와 mmap같은 것들에는 사용할 수 없습니다 .
MAP_HASSEMAPHORE은 BSD에만 해당됩니다.
mmap ()이 유리하지 않은 영역 중 하나는 작은 파일을 읽을 때 (16K 미만)였습니다. 전체 파일을 읽는 데 실패한 페이지 오버 헤드는 단일 read () 시스템 호출을 수행하는 것과 비교하여 매우 높습니다. 커널이 때때로 타임 슬라이스에서 읽기를 완전히 만족시킬 수 있기 때문에 코드가 바뀌지 않습니다. 페이지 오류로 인해 다른 프로그램이 예약되어 파일 작업의 대기 시간이 길어질 가능성이 높아졌습니다.
malloc메모리 조각 보다 빠르며 1 read로 만듭니다 . 이것은 malloc'ed 처리하는 메모리 맵을 처리하는 동일한 코드를 가질 수 있습니다.
read액세스 오버 헤드가 가상 메모리 조작의 오버 헤드보다 높 도록 특정 크기의 맵이 필요합니다 .
mmap경우 페이지 테이블에서 4 개의 항목을 업데이트해야합니다. 그러나 read16K의 버퍼에 복사 하는 데 사용 하려면 4 개의 페이지 테이블 항목도 업데이트해야하며 16K를 사용자 추가 공간에 복사해야합니다. 따라서 페이지 테이블에서 작업의 차이점과 비용이 얼마나 비싼 지 자세히 설명 할 수 mmap있습니까?
mmap큰 파일에 무작위로 액세스 할 때 이점이 있습니다. 또 다른 장점은 버퍼링에 신경 쓰지 않고 메모리 작업 (memcpy, 포인터 산술)으로 액세스한다는 것입니다. 버퍼보다 큰 구조를 가지고있을 때 버퍼를 사용할 때 일반 I / O가 매우 어려울 수 있습니다. 처리하기 어려운 코드는 종종 제대로 이해하기 어렵습니다. mmap은 일반적으로 더 쉽습니다. 이것으로 작업 할 때 특정 함정이 있다고 말했습니다 mmap. 사람들이 이미 언급했듯이 mmap설정하는 데 비용이 많이 들기 때문에 주어진 크기 (기계마다 다름)에만 사용할 가치가 있습니다.
파일에 대한 순차 순차 액세스의 madvise경우 문제를 완화 하기위한 적절한 호출이 항상 더 나은 솔루션 은 아닙니다.
읽기 / 쓰기 IO를 사용하면 아키텍처 (SPARC, 아이테니엄)의 정렬 제한에주의해야합니다. 읽기 / 쓰기 IO를 사용하면 버퍼가 올바르게 정렬되고 캐스트 된 포인터를 역 참조 할 때 트랩되지 않습니다.
또한지도 외부에 액세스하지 않도록주의해야합니다. 맵에서 문자열 함수를 사용하고 파일 끝에 \ 0이 없으면 쉽게 발생할 수 있습니다. 마지막 페이지가 0으로 채워져 파일 크기가 페이지 크기의 배수가 아닌 경우 대부분 작동합니다 (매핑 된 영역은 항상 여러 페이지 크기의 크기 임).
다른 좋은 답변 외에도 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( )매핑 된 파일이 크거나 (따라서 낭비되는 공간이 전체 매핑의 작은 비율 인 경우) 또는 매핑 된 파일의 총 크기가 페이지 크기로 균등하게 나올 때 이점 이 가장 크게 실현됩니다 ( 따라서 낭비되는 공간이 없습니다).
메모리 매핑은 기존 IO에 비해 속도가 크게 향상 될 수 있습니다. 메모리 맵핑 파일의 페이지가 터치 될 때 운영 체제가 소스 파일에서 데이터를 읽을 수 있습니다. 이는 운영 체제가 감지 한 후 OS가 파일에서 해당 데이터를 자동으로로드하는 오류 페이지를 작성하여 작동합니다.
이는 페이징 메커니즘과 동일한 방식으로 작동하며 일반적으로 대부분의 파일 시스템 캐시에 최적화 된 크기 인 시스템 페이지 경계 및 크기 (일반적으로 4K)의 데이터를 읽음으로써 고속 I / O에 최적화됩니다.
pread. Solaris 9 Sparc (V890)에서 프리 어드 액세스는 memcpymmap 보다 2 ~ 3 배 느립니다 . 그러나 순차 액세스는 필연적으로 더 빠르지 않습니다.
아직 나열되지 않은 장점은 mmap()읽기 전용 매핑을 깨끗한 페이지 로 유지할 수 있다는 것입니다 . 프로세스의 주소 공간에 버퍼를 할당 한 다음 read()파일에서 버퍼를 채우는 데 사용 하는 경우 해당 버퍼에 해당하는 메모리 페이지 는 기록 된 이후 더티 입니다.
커널은 더티 페이지를 RAM에서 삭제할 수 없습니다. 스왑 공간이 있으면 스왑 공간을 페이징하여 스왑 할 수 있습니다. 그러나 이는 비용이 많이 들고 플래시 메모리 만있는 소형 임베디드 장치와 같은 일부 시스템에서는 스왑이 전혀 없습니다. 이 경우 프로세스가 종료 될 때까지 버퍼가 RAM에 갇히거나으로 다시 반환 될 수 madvise()있습니다.
mmap()페이지에 쓰지 않은 것이 깨끗합니다. 커널에 RAM이 필요한 경우 간단히 삭제하고 페이지에 있던 RAM을 사용할 수 있습니다. 매핑이있는 프로세스가 다시 액세스하면 페이지 오류가 발생하여 커널이 원래 가져온 파일에서 페이지를 다시로드합니다 . 처음부터 같은 방식으로 채워졌습니다.
이를 위해서는 매핑 된 파일을 사용하는 프로세스가 두 개 이상 필요하지 않습니다.
read()데이터가 들어가는 페이지는 원래 가져온 파일과 아무 관련이 없습니다. 따라서 스왑 공간을 제외하고는 쓸 수 없습니다. 파일이 mmap()ed이고 매핑이 쓰기 가능하고 (읽기 전용이 아니라) 쓰기 인 경우 매핑이 MAP_SHARED또는 에 해당하는지 여부에 따라 다릅니다 MAP_PRIVATE. 공유 매핑은 파일에 쓸 수 있어야하지만 개인용으로는 쓸 수 없습니다.