반응형

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



* 메모리 맵 - mmap() <파일 혹은 디바이스를 메모리와 대응>

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

 

 

* 특징

1. 생성된 메모리 맵을 포인터를 이용하여 쉽게 사용 가능하다.

2. 파일로 연결하여 사용시 메모리-파일 사이의 동기화가 편하다.

3. IPC(프로세스간 통신)로 활용 가능하다.

4. 대용량의 데이터를 사용할 시 성능이 향상된다.

 

* 주의점

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

 IPC로 사용 할 때에도 프로세스간 동기화에 대한 주의도 필요하다.


* 2가지 방식

1. 공유 메모리 맵 방식 (Shred Memory-Map)

; 메모리 맵 변경 시 원본 파일과 데이터가 동기화가 되는 방식

2. 복사 메모리 맵 방식 (Private Memory-Map)

; 처음 메모리 맵에 매핑 될때 파일의 내용을 읽어와서 복사하고 그 이후 동기화 하지 않는 방식.

 

 

* 메모리 맵 생성 함수 - mmap()

 

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

 

- void *state

; 할당받기 원하는 메모리 주소. 보통 0을 써서 커널이 적합한 공간을 임의로 할당해 주소를 받을 수 있고, 직접 입력하여 사용해도된다. 하지만 직접 입력하는 경우 해당 시스템의 페이지 (배수)단위로 주소 값을 설정해줘야 한다.

 

- size_t length

; 메모리 맵을 할 크기. 바이트 단위로 설정한다.

 

- int prot

; 메모리 보호 메커니즘. 플래그 형식이므로 비트 연산으로 복수 속성으로 지정 가능하다.

 + PROT_EXEC; 해당 페이지 실행 가능.

 + PROT_READ; 해당 페이지 읽기 가능.

 + PROT_WRITE; 해당 페이지 쓰기 가능.

 + PROT_NONE; 해당 페이지 접근 불가.

 => 매핑할 파일 디스크립터와 속성이 같아야한다.

 

- int flags

 + MAP_SHARED; 공유 메모리 맵 방식.

 + MAP_PRIVATE; 복사 메모리 맵 방식.

 + MAP_FIXED ; 메모리 시작 번지 지정시 사용.

 =>MAP_SHARED/MAP_PRIVATE 둘 중에 한개만 지정해야된다.

 

- int fd

 ; 메모리 맵 방식을 사용할 파일 디스크립터.(파일 혹은 디바이스)

 

- ott_t offset

 ; 해당 파일 디스크립터에서 메모리 맵을 시작할 오프셋 값.



p style="margin-right: 0px; margin-left: 0px; padding: 0px; line-height: 20px; color: rgb(72, 72, 72); text-align: justify; ">+ return value

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

 

 

* 메모리 맵 해제 - munmap()

; 메모리 맵을 사용하고 자원을 해제 할 때 사용한다.

 

int munmap(void *start, size_t length);

 

- void *start

; 메모리 맵핑이 시작된 주소. mmap()의 반환 값을 넣으면된다.

 

- size_t length

; 메모리 맵을 한 길이. mmap() 사용시 size_t length 인자와 크기를 주면된다.

 

+ return value

;성공 0, 실패 -1

 

 

* 메모리 맵과 파일의 동기화 - fsync()

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

 

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

 

- void *start

; mmap()를 통해 리턴 받은 메모리 맵의 시작 주소.

 

-  size_t length

; 동기화를 할 길이. 시작 주소로 부터 길이를 지정하면 된다.

 

- int flags

 + MS_ASYNC

 ; 비동기 방식. 동기화(Memory->File)하라는 명령만 내리고 결과에 관계 없이 바로 리턴.

   그렇기 때문에 동기화가 된 건지 알수 없다.

 + MS_SYNC

 ; 동기 방식. 동기화(Memory->File)가 될때까지 블럭 상태로 대기한다.

 + MS_INVALIDATE

 ; 현재 메모리 맵을 무효화하고 파일의 데이터로 갱신. 즉 File->Memory

 

 

===================================================================================

       ...

#define MMAP_FULENAME "test_mmap"

#define MMAP_SIZE 64

       ...

int main()

{

     int fd;

     char *p_mmap;      //메모리 맵으로 사용할 데이터 타입

       ...

     fd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0664);

       ...

     p_mmap = (char*)mmap((void*)0, MMAP_SIZE, PROT_READ|PROT_WRITE,

                                                                     MAP_SHARED, fd, 0);

     //공유 메모리 방식을 사용한다. 읽기/쓰기 가능

       ...

     //memcpy(); 등으로 메모리 맵 데이터 갱신.

       ...

     msync(p_mmap, MAP_SIZE, MS_SYNC);

       ...

     munmap(p_mmap);

     return 0;

}

  

=> 메모리 맵 할 파일 이름만 같으면 IPC도 된다.


------------------------------------------------------------

출처 : http://hsnote.tistory.com/141


윈도우의 경우는 아래의 자료를 참고.




[메모리 매핑파일]


HANDLE CreateFileMapping(HANDLE hFile,    // (1)
   LPSECURITY_ATTRIBUTES lpAttributes, //(2)
   DWORD flProtect,  // (3)
   DWORD dwMaximumSizeHigh,  // (4)
   DWORD dwMaxImumSizeLow,  // (5)
   LPCTSTR lpName   //(6)
   );


위의 함수가 매모리매핑 파일을 만드는 함수이다..

위의 함수 사용시 매모리맵파일이 생성은 되지만 실제로 매모리에 연결되어 있진않다. 

연결을 하려면 MapViewOfFile 이라는 함수를 써야지 그 때부터 메모리에 연결이 된다.

일단위 함수의 설명을 들어보자

 

목적 및 하는 일 : MMF라는 커널 객체를 만들고 그 핸들을 리턴한다.
                         메모리매핑파일을 만들수있는 기본정보들을 갖고 있는 커널객체를 만들고 그 핸들을 리턴한다.


인자설명 : 
 (1) hFile  : CreateFile 함수로 해당파일을 열고 리턴받은 값.. (CreaqteFile 의 리턴값  파일핸들) 파일핸들을 인자로 넘겨준다.. , (어떤파일을 파일매핑할건지 정하는거다.)
 
 (2) lpAttributes : 솔직히 잘 모르겠는데 .. 보통 이값은 NULL로 줬다. (아시는 분은 좀 알려주세여^^)

 (3) flProtect : 읽기 전용으로 할건지 읽기 쓰기를 할건지 설정하는 옵션이다. ex) PAGE_READONLY, PAGE_READWRITE 등등

 (3) dwMaximumSizeHigh : 매핑할 범위를 지정하는 상위 4바이트 (용량이 작은 범위라면 이곳에 0을 주고 그 다음 인자에 파일크기 및 원하는 범위를 지정한다.)
 
 (4) dwMaximumSizeLow : 매핑할 범위 지정하는 하위 4바이트

 (5) lpName : 파일매핑 객체이기 때문에 객체에 이름을 부여할때 쓴다. 보통   NULL을 주고 이름을 붙이도 다른곳에서 참조할때는 이름을 문자열로 이름을 지정한다.


사용예제 ) CreateFileMapping(hSource, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
 
 CreateFileMapping(hTarget, NULL, PAGE_READWRITE, 0, dwFileSize, NULL);


------------------------------------------------------------------------------------------------------------------------------


LPVOID MapViewOfFile(HANDLE hFileMappingObject, // (1)
   DWORD dwDesiredAccess,  // (2)
   DWORD dwFileOffsetHigh,  //(3)
   DWORD dwFileOffsetLow,   // (4)
   SIZE_T dwNumberOfBytesToMap   // (5)
  );

목적 및 하는 일 : CreateFileMapping 함수로 만든 MMF 객체를 대상으로 실제 메모리번지에 연결을 하여 메모리 매핑파일을 만든다.
  메모리 매핑파일 만들고 그 메모리의 시작번지를 리턴한다.


인자설명 :
 (1) hFileMappingObject : CreateFileMapping 함수로 리턴받은 핸들값을 인자로 준다.

 (2) dwDesireAccess : 접근권한을 설정하는 것으로 FILE_MAP_READ, FILE_MAP,WRITE 등으로 옵션을 준다.

 (3) dwFileOffsetHigh :  메모리 주소가 연결될 크기 상위 4바이트

 (4) dwFileOffsetLow : 메모리 주소가 연결될 크기 하위 4바이트

 (5) dwNumberOfBytesToMap : 오프셋으로 부터 원하는 크기를 정한다.

사용예제 ) MapViewOfFile(hMapSource, FILE_MAP_READ, 0, dwAs, dwLen);

 MapViewOfFile(hMapTarget, FILE_MAP_WRITE, 0, dwAs, dwLen);


------------------------------------------------------------------------------------------------------------------------------

해당함수들을 사용후에는 해제 해주어야 하는데

CreateFileMapping 함수 같은 경우 파일 핸들을 리턴함으로

CloseHandle(리턴값); 으로 해제하고

MapViewOfFile 함수 같은 경우는 메모리 주소를 리턴함으로

UnmapViewOfFile(리턴값); 으로 해제한다.

------------------------------------------------------------------------------------------------------------------------------ 

반응형

+ Recent posts