저는 프로젝트를 위해 메모리 매핑 파일을 연구 해 왔으며 이전에 사용했거나 사용하지 않기로 결정한 사람들의 의견을 고맙게 생각하며 그 이유는 무엇입니까?
특히 다음 사항이 중요합니다.
- 동시성
- 랜덤 액세스
- 공연
- 사용의 용이성
- 휴대 성
답변:
기존의 파일 읽기 방법에 비해 필요한 데이터 복사량을 줄이는 것이 장점이라고 생각합니다.
응용 프로그램이 메모리 매핑 된 파일의 "제자리"에서 데이터를 사용할 수 있으면 복사하지 않고도 가져올 수 있습니다. 시스템 호출 (예 : Linux의 pread ())을 사용하는 경우 일반적으로 커널이 자체 버퍼에서 사용자 공간으로 데이터를 복사하는 작업이 포함됩니다. 이 추가 복사는 시간이 소요될뿐만 아니라이 추가 데이터 사본에 액세스하여 CPU 캐시의 효율성을 감소시킵니다.
실제로 디스크에서 데이터를 읽어야하는 경우 (물리적 I / O에서와 같이) OS는 여전히 데이터를 읽어야합니다. 페이지 오류는 시스템 호출보다 성능면에서 더 좋지 않을 수 있습니다. 하지 마십시오 (예 : 이미 OS 캐시에 있음). 이론상 성능이 훨씬 좋아야합니다.
단점은 메모리 매핑 파일에 대한 비동기 인터페이스가 없다는 것입니다. 매핑되지 않은 페이지에 액세스하려고하면 페이지 폴트가 생성되고 스레드가 I / O를 기다리게됩니다.
메모리 매핑 파일의 명백한 단점은 32 비트 OS에 있다는 것입니다. 주소 공간이 쉽게 부족해질 수 있습니다.
사용자가 입력하는 동안 '자동 완성'기능을 구현하기 위해 메모리 매핑 파일을 사용했습니다. 단일 색인 파일에 1 백만 개가 넘는 제품 부품 번호가 저장되어 있습니다. 파일에는 몇 가지 일반적인 헤더 정보가 있지만 파일의 대부분은 키 필드에 정렬 된 고정 크기 레코드의 거대한 배열입니다.
런타임에 파일은 메모리 매핑되고 C
스타일 struct
배열로 캐스트 되며 사용자가 입력 할 때 일치하는 부품 번호를 찾기 위해 이진 검색을 수행합니다. 파일의 몇 개의 메모리 페이지 만 실제로 디스크에서 읽습니다.
메모리 매핑 파일은 읽기 / 쓰기 액세스를 대체하거나 동시 공유를 지원하는 데 사용할 수 있습니다. 한 메커니즘에 사용하면 다른 메커니즘도 얻게됩니다.
파일을 찾고 쓰고 읽는 대신 메모리에 매핑하고 예상되는 비트에 액세스하기 만하면됩니다.
이것은 매우 편리 할 수 있으며 가상 메모리 인터페이스에 따라 성능을 향상시킬 수 있습니다. 이제 운영 체제가 다른 모든 프로그래밍 방식 메모리 액세스와 함께 이전의 "파일 I / O"를 관리하고 (이론적으로) 페이징 알고리즘 등을 활용할 수 있기 때문에 성능이 향상 될 수 있습니다. 나머지 프로그램을 위한 가상 메모리 . 그러나 기본 가상 메모리 시스템의 품질에 따라 다릅니다. 내가 들었던 일화는 Solaris와 * BSD 가상 메모리 시스템이 Linux의 VM 시스템보다 더 나은 성능 향상을 보여줄 수 있다고 말했지만이를 뒷받침 할 경험적 데이터가 없습니다. YMMV.
매핑 된 메모리를 통해 동일한 "파일"을 사용하는 여러 프로세스의 가능성을 고려할 때 동시성이 나타납니다. 읽기 / 쓰기 모델에서 두 프로세스가 파일의 동일한 영역에 쓴 경우 프로세스의 데이터 중 하나가 파일에 도착하여 다른 프로세스의 데이터를 덮어 쓰는 것이 거의 확실합니다. 당신은 하나 또는 다른 것을 얻을 수 있지만 이상한 혼합은 아닙니다. 나는 이것이 어떤 표준에서 요구하는 행동인지 확실하지 않지만 당신이 거의 의지 할 수있는 것임을 인정해야합니다. (실제로 좋은 후속 질문입니다!)
대조적으로, 매핑 된 세계에서 "쓰기"두 가지 과정을 상상해보십시오. 그들은 "메모리 저장소"를 수행하여이를 수행하며 결과적으로 O / S가 데이터를 디스크로 페이징합니다. 그러나 그 동안 겹치는 쓰기가 발생할 수 있습니다.
여기에 예가 있습니다. 오프셋 1024에서 8 바이트를 쓰는 두 개의 프로세스가 있다고 가정 해 보겠습니다. 프로세스 1은 '11111111'을 쓰고 프로세스 2는 '22222222'를 쓰고 있습니다. 그들이 파일 I / O를 사용한다면, 당신은 상상할 수 있습니다. O / S의 깊숙한 곳에는 1로 가득 찬 버퍼와 2로 가득 찬 버퍼가 모두 디스크의 같은 위치로 향하고 있습니다. 그들 중 하나가 먼저 거기에 도착하고 다른 하나가 1 초에 도착합니다. 이 경우 두 번째 사람이 이깁니다. 그러나 메모리 매핑 된 파일 접근 방식을 사용하는 경우 프로세스 1은 4 바이트의 메모리 저장소로 이동 한 다음 4 바이트의 다른 메모리 저장소로 이동합니다 (최대 메모리 저장소 크기가 아니라고 가정 해 보겠습니다). 프로세스 2는 동일한 작업을 수행합니다. 프로세스가 실행되는시기에 따라 다음 중 하나를 볼 수 있습니다.
11111111
22222222
11112222
22221111
이에 대한 해결책은 명시 적 상호 배제를 사용하는 것입니다. 이는 어떤 경우에도 좋은 생각입니다. 어쨌든 읽기 / 쓰기 파일 I / O의 경우 "올바른 일"을 수행하기 위해 O / S에 의존하고있었습니다.
분류 상호 배제 프리미티브는 뮤텍스입니다. 메모리 매핑 파일의 경우 pthread_mutex_init ()를 사용하여 사용할 수있는 메모리 매핑 된 뮤텍스를 살펴 보는 것이 좋습니다.
단 하나의 문제로 편집 : 매핑 된 파일을 사용할 때 파일 자체에있는 데이터에 대한 포인터를 포함하려는 유혹이 있습니다 (매핑 된 파일에 저장된 연결 목록을 생각해보십시오). 파일이 다른 시간 또는 다른 프로세스에서 다른 절대 주소에 매핑 될 수 있으므로 그렇게하고 싶지 않습니다. 대신 매핑 된 파일 내에서 오프셋을 사용하십시오.