■ 표준 입출력 대안으로, 커널은 응용이 파일을 메모리에 맵핑하는 인터페이스를 제공한다. 이는 메모리 주소와 파일 워드 사이에 1 대 1 대응을 의미한다.


(1) 프로세스와 메모리관리
: 메모리관리와 mmap 각각의 프로세스는 프로세스마다 다른 프로세스와 중복되지 않는 주소공간을 가지게 된다. 주소 공간은 최초 논리적인 3개의 세그먼트로 분할된다.
 
[TEXT], [DATA], [STACK]

텍스트 세그먼트는 읽기전용으로 프로그램의 명령을 포함하고 있다. 데이터와 스택 세크먼트는 읽기,쓰기가 모두 가능한 영역이다. 차이점이라면 데이터 세그먼트에는 초기화 된 데이터와 그렇지 않은 데이터가 함께 있는데 반해, 스택 세그먼트는 실행시간에 초기화된 값들을 보관한다는 것이다. 대부분의 시스템에서는 프로세스의 실행과 함께 커널에 의해서 스택 세그먼트가 자동으로 확장된다. 데이터 세그먼트의 경우는 malloc()계열의 시스템콜을 이용해서 확장하는 것이 가능하다. 텍스트 세그먼트의 경우 디버깅과 같은 제한된 환경에서 크기의 변경이 가능하다.


(2) mmap()

: mmap() 호출은 파일기술자 fd가 가리키는 객체를 파일에서 offset 바이트 지점을 기준으로 len 바이트만큼 메모리에 맵핑하도록 커널에 요청한다. addr을 넘길 경우, 메모리에서 해당 시작 주소를 선호한다고 커널에게 알린다. 접근 권한은 prot에 지정하고, 추가적인 동작 방식은 flags에 지정한다.

● 함수 원형

#include <sys/mman.h>

void * mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset);

* return 값 : 맵핑이 시작하는 실제 메모리 주소


○ addr : 커널에게 파일을 어디에 맵핑하면 좋을지 제안하는 값 (보통 0 사용)

○ len : 맵핑시킬 메모리 영역의 길이

○ prot : 맵핑에 원하는 메모리 보호 정책 (읽기 전용으로 열었다면 PROT_WRITE를 지정하면 안된다.)
  - PROT_READ : 읽기 가능한 페이지
  - PROT_WRITE : 쓰기 가능한 페이지
  - PROT_EXEC : 실행 가능한 페이지
  - PROT_NONE : 접근할 수 없는 페이지

○ flags : 맵핑 유형과 동작 구성 요소
  - MAP_FIXED : addr과 len 매개변수가 기존 맵핑과 겹칠경우 중첩 페이지를 버리고 새 맵핑으로 대체. (권장하지 않음)
  - MAP_SHARED : 동일 파일을 맵핑한 모든 프로세스들이 공유. 객체 접근에 대한 동기화를 위해 msync, munmap을 사용.
  - MAP_PRIVATE : 맵핑을 공유하지 않아, 파일은 쓰기 후 복사로 맵핑되며, 변경된 메모리 속성은 실제 파일에는 반영되지 않음.

○ fd : 파일기술자

○ offset : 맵핑할 때 len의 시작점을 지정


(3) munmap()
: mmap()으로 만들어진 맵핑을 제거하기 위한 시스템 호출.

● 함수 원형

#include <sys/mman.h>

int * munmap (void *addr, size_t len);

* return 값 : 성공 0, 실패 -1

: munmap() 호출은 addr에서 시작하는 프로세스 주소 공간에 위치한 페이지를 포함하는 모든 맵핑을 제거한다. 이 영역은 len 바이트
만큼 계속해서 이어져야 하며, 페이지에 정렬되어 있어야 한다. 


(4) mmap()의 장단점

● 장점
- 메모리 맵핑 파일에 읽고 쓰는 방식은 read()나 write() 시스템 호출을 사용할 때 일어나는 추가 복사를 방지한다.
   여기서 추가 복사가 일어나는 이유는 사용자 영역 버퍼로 자료를 직접읽고 써야하기 때문이다.
- 잠재적인 페이지 폴트 가능성을 제외하고는 메모리 맵핑 파일에서 읽고 쓰는 방식은 시스템 호출이나 문맥 전화 부하가 발생하지 않는다. 메모리 접근만큼이나 단순하다.
- 다중 프로세스가 동일 객체를 메모리에 맵핑할 때, 모든 프로세스가 자료를 공유한다. 읽기만 가능하거나 쓰기 가능한 공유 맵핑은 완전한 상태로 공유된다. 특정 프로세스 전용(private) 쓰기 맵핑은 쓰기 후 복사가 일어나기 전까지만 페이지를 공유한다.
- 맵핑된 영역 탐색은 간단한 포인터 조작으로 끝낸다. lseek() 시스템 호출이 필요하지 않다.

● 단점
- 메모리 맵핑의 크기는 페이지 단위 정수배만 가능하다. 따라서 맵핑하려는 파일 크기와 페이지의 정수배 크기 사이에 벌어진 차이는 여분의 공간으로 '낭비'된다. 작은 파일이라면 맵핑 때문에 상당히 많은 공간이 낭비될 가능도 있다. 예를 들어 4KB 페이지에서 7바이트 사상은 4,089바이트가 낭비된다.
- 메모리 맵핑은 프로세스 주소 공간에 맞아 떨어져야 한다. 32비트 주소 공간에서 크기가 각기 다른 맵핑이 상당히 많다면 주소 공간 단편화를 초래하므로 비어 있는 충분히 크고 연속적인 공간을 찾아내기가 어려워진다. 물론 64비트 주소 공간에서는 그다지 문제가 되지 않는다.
- 메모리 맵핑과 관련 자료 구조를 커널 내부에서 만들고 관리하는 작업에는 부하가 발생한다. 큰 파일에 자주 접근할 경우 일반적으로 이중복사 제거하는 방법으로 부하를 방지한다.


(5) 예제 소스 / 결과

○ Source Code



○ test file
 


○ Result 


내용이 메모리에 대응되는 것을 확인 할 수 있다.


※ 추가 mmap 참고 자료
2011/04/19 - [P rogramming/Linux System] - mmap(), munmap(), msync() - 메모리맵

'P rogramming > Linux System' 카테고리의 다른 글

시그널의 등록과 처리  (0) 2012.05.21
파일 컨트롤 함수 :: fcntl()  (0) 2012.05.15
오류처리 - perror(), strerror()  (0) 2012.03.06
파일 읽기 - read()  (0) 2012.03.06
파일 쓰기 - write()  (0) 2012.03.06
by 민트앤라떼 2012. 4. 24. 14:15