답변:
mmap
동일한 파일에서 읽기 전용 방식으로 데이터에 액세스하는 여러 프로세스가있는 경우 좋습니다. 이는 내가 쓰는 서버 시스템 종류에서 일반적입니다. mmap
이러한 모든 프로세스가 동일한 실제 메모리 페이지를 공유하여 많은 메모리를 절약 할 수 있습니다.
mmap
또한 운영 체제에서 페이징 작업을 최적화 할 수 있습니다. 예를 들어, 두 개의 프로그램을 고려하십시오. 로 생성하는 버퍼로 파일 A
을 읽는 프로그램 과 1MB 파일을 메모리로 1MB
만드는 malloc
프로그램 B. mmaps
운영 체제가 A
의 메모리 일부를 교체 해야하는 경우 메모리를 재사용하기 전에 교체 할 버퍼의 내용을 써야합니다. 년 B
의 경우 어떤 수정되지 않은 mmap
OS가 그들이 있던 기존 파일에서 복원하는 방법을 알고 있기 때문에 '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 개의 항목을 업데이트해야합니다. 그러나 read
16K의 버퍼에 복사 하는 데 사용 하려면 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)에서 프리 어드 액세스는 memcpy
mmap 보다 2 ~ 3 배 느립니다 . 그러나 순차 액세스는 필연적으로 더 빠르지 않습니다.
아직 나열되지 않은 장점은 mmap()
읽기 전용 매핑을 깨끗한 페이지 로 유지할 수 있다는 것입니다 . 프로세스의 주소 공간에 버퍼를 할당 한 다음 read()
파일에서 버퍼를 채우는 데 사용 하는 경우 해당 버퍼에 해당하는 메모리 페이지 는 기록 된 이후 더티 입니다.
커널은 더티 페이지를 RAM에서 삭제할 수 없습니다. 스왑 공간이 있으면 스왑 공간을 페이징하여 스왑 할 수 있습니다. 그러나 이는 비용이 많이 들고 플래시 메모리 만있는 소형 임베디드 장치와 같은 일부 시스템에서는 스왑이 전혀 없습니다. 이 경우 프로세스가 종료 될 때까지 버퍼가 RAM에 갇히거나으로 다시 반환 될 수 madvise()
있습니다.
mmap()
페이지에 쓰지 않은 것이 깨끗합니다. 커널에 RAM이 필요한 경우 간단히 삭제하고 페이지에 있던 RAM을 사용할 수 있습니다. 매핑이있는 프로세스가 다시 액세스하면 페이지 오류가 발생하여 커널이 원래 가져온 파일에서 페이지를 다시로드합니다 . 처음부터 같은 방식으로 채워졌습니다.
이를 위해서는 매핑 된 파일을 사용하는 프로세스가 두 개 이상 필요하지 않습니다.
read()
데이터가 들어가는 페이지는 원래 가져온 파일과 아무 관련이 없습니다. 따라서 스왑 공간을 제외하고는 쓸 수 없습니다. 파일이 mmap()ed
이고 매핑이 쓰기 가능하고 (읽기 전용이 아니라) 쓰기 인 경우 매핑이 MAP_SHARED
또는 에 해당하는지 여부에 따라 다릅니다 MAP_PRIVATE
. 공유 매핑은 파일에 쓸 수 있어야하지만 개인용으로는 쓸 수 없습니다.