메모리 맵
파일(리눅스에서는 디바이스도 파일로 처리하므로 디바이스도 메모리 맵으로 연결 가능)을 처리하기 위해서는 보통 저수준으로는 파일 디스크립터를 사용하고, 고수준으로 접근하기 위해서는 파일 구조체 포인터를 이용하여 접근하게 된다.
하지만 이런 방식을 이용하면 버퍼를 거쳐서 실제 입출력을 하게 되는데, mmap()을 이용하여,메모리 맵 방식으로 파일을 연결하게 되면 버퍼를 이용하는 것이 아니라 '페이지(page)'를 이용하여 데이터 처리가 가능해진다.
상대적으로 크기가 작은 버퍼에 비해 4KB의 크기를 가지는 페이지를 이용하면 처리 가능한 크기와 처리 속도가 향상된다.
그렇기 때문에 데이터 크기가 크거나 빠른 처리를 해야하는 경우 메모리 맵 방식을 종종 사용하게 된다. 메모리 맵을 사용하면 처리 속도가 빨라지는 예가 바로 처리하는 데이터가 큰 동영상을 봉 때이다. 그리고 실제 실행 파일도 윈도우든, 리눅스든 실행 할 때 페이지로 분할되므로 메모리 맵 방식으로 맵핑된다. 대표적으로 코드 영역은 데이터의 변경이 없기 때문에,메모리 맵을 이용해 맵핑 하면서 처리 속도는 물론이고 메모리 낭비도 없앨 수 있다.

특징
   1. 생성된 메모리 맵을 포인터를 이용하여 쉽게 사용 가능하다.
   2. 파일로 연결하여 사용 시 메모리-파일 사이의 동기화가 편하다.
   3. IPC로 활용 가능하다.
   4. 대용량의 데이터를 사용할 시 성능이 향상 된다.

주의점
   메모리 맵은 바로 파일에 처리하는게 아니라 가상 메모리로 활용되는 페이지에 맵핑하는 방식이다.
   따라서 파일과 해당 메모리 맵이 된 페이지가 다른공간 이다. 그러므로 커널에 의해 여유 시간에 동기화가 될 때까지 서로
   다른 데이터를 가질 수 있으므로, 동기화에 대한 주의가 필요하다.
   < 개발자가 직접 커널에 동기화를 명령할 수 있는 함수도 있다. - fsync() >

2가지 방식
   1. 공유 메모리 맵 방식 - 메모리 맵 변경 시 원본 파일과 데이터가 동기화 되는 방식
   2. 복사 메모리 맵 방식 - 처음 메모리 맵에 맵핑 될 때 파일의 내용을 읽어와서 복사하고 그 이후 동기화 하지 않는 방식.



 mmap() - 메모리 맵 생성

  
void* mmap(void *state, size_t length, int prot, int flags, int fd, ott_t offset)

1. state : 할당받기 원하는 메모리 주소. 보통 0을 써서 커널이 적합한 공간을 임의로 할당해 주소를 받을 수도 있고,
             직접 입력하여 사용해도 된다. 직접 입력 할 경우 해당 시스템의 페이지 (배수)단위로 주소 값을 설정해주어야 한다.
2. length : 메모리 맵 할당 크기. 바이트 단위로 설정한다.
3. int prot : 메모리 보호 메커니즘. 플래그 형식으로 비트 연산으로 복수 속성으로 지정 가능하다.
   - PROT_EXEC : 해당 페이지 실행 가능.
   - PROT_READ : 해당 페이지 읽기 가능.
   - PROT_WRITE : 해당 페이지 쓰기 가능.
   - PROT_NONE : 해당 페이지 접근 불가.
   => 맵핑할 파일 디스크립터와 속성이 같아야 한다.
4. flags : 방식
   - MAP_SHARED : 공유 메모리 맵 방식.
   - MAP_PRIVATE : 복사 메모리 맵 방식.
   - MAP_FIXED : 메모리 시작 번지 지정시 사용.
   => MAP_SHARED or MAP_PRIVATE 둘 중 한개만 지정해야 한다.
5. fd : 메모리 맵 방식을 사용할 파일 디스크립터.(파일 혹은 디바이스)
6. offset : 해당 파일 디스크립터에서 메모리 맵을 시작할 오프셋 값.

return 값 : 매모리 맵핑이 이루어진 가상 메모리 주소. 실패시 MAP_FAILED가 발생하고 errno에 해당 상황에 대한 값이 설정 된다.


 munmap() - 메모리 맵 자원 해제

   int munmap(void *start, size_t length)

1. start : 메모리 맵핑이 시작된 주소. mmap()의 반환값.
2. length : 메모리 맵 길이. mmap() 사용시 length 인자값.

return 값 : 성공 0, 실패 -1


 msync() - 동기화
   메모리 맵에 데이터를 갱신해도 바로 파일과 동기화가 이루어지는 것은 아니다. 커널이 여유 있을 때 동기화를 수행한다.
   그러므로 개발자가 직접 동기화를 보장하고 싶을 때 사용한다. 그리고 munmap()을 하여 메모리 맵을 해제 할 때에도
   데이터가 보장된다.

   int msync(void *start, size_t length, int flags)

1. start : mmap()을 통해 리턴 받은 메모리 맵의 시작 주소.
2. length : 동기화를 할 길이.
3. flags
   - MS_ASYNC : 비동기 방식. 동기화하라는 명령만 내리고 결과에 관계없이 바로 리턴. 결과 알수없다. Memory->File
   - MS_SYNC : 동기 방식. 동기화가 될때까지 블럭 상태로 대기한다. Memory->File
   - MS_INVALIDATE : 현재 메모리 맵을 무효화 하고, 파일의 데이터로 갱신. File->Memory





※ 출처 : http://no1rogue.blog.me/30097158983

by 민트앤라떼 2011. 4. 19. 11:49