오랜만에 MMF (Memory Mapped File)를 살펴볼 일이 있어 예전 자료를 찾아다 쓰면서.. 

이것 저것 실험하는 중 불편한 코드 정리 및 대충 알던거 살펴보기.. 잘모르던거 제대로 알기.. 

이런 저런 관점에서 정리해보는 글입니다.


MMF가 무엇인지 어떤 장단점을 가지고 있는지와 관련된 내용이나 참조 사항은 다음 링크..

위키 : http://ko.wikipedia.org/wiki/메모리_맵_파일

이전자료 : http://crowback.tistory.com/198

MSDN : http://msdn.microsoft.com/en-us/library/ms810613.aspx


우선 정리된 클래스 골격



class CMMFObject

{
#define BIGINT LARGE_INTEGER

public:
    CMMFObject()
    {
        m_FileSize.QuadPart = 0;
        m_FileHandle        = INVALID_HANDLE_VALUE;
        m_hMemoryMap        = NULL;
        m_pMemoryMap        = NULL;
        m_bAudoDelete       = false;
        m_FilePath[0]       = 0;
    }

    virtual ~CMMFObject() { Close(); }


    /* 만들어져 있는 MMF를 열 때 사용하는 열기 함수 */
    DWORD Open(const TCHAR* pszMapName, DWORD dwDesiredAccess = FILE_MAP_READ);


    /* 파일 핸들이 있거나 시스템 페이지를 이용하여 MMF를 생성하는 함수 */
    DWORD Create(HANDLE hFile, const TCHAR* pszMapName, LONGLONG iFilesize, LPSECURITY_ATTRIBUTES lpAttributes = NULL);


    /* 파일을 직접 지정하여 MMF를 생성하는 함수 */
    DWORD Create(const TCHAR* pszMapFilePath, const TCHAR* pszMapName, LONGLONG iFilesize, bool bAudoDelete = true, LPSECURITY_ATTRIBUTES lpAttributes = NULL);


    /* 열려 있는 모든 내부정보를 닫고, 초기화 */

    DWORD Close(DWORD rc = ERROR_SUCCESS);


    /* 생성된 MMF의 접근 가능한 주소 */

    LPBYTE GetPtr() { return m_pMemoryMap; }

protected:

    DWORD __MapViewOfFile(DWORD dwDesiredAccess )
    {
        m_pMemoryMap = (BYTE*)::MapViewOfFile(m_hMemoryMap, dwDesiredAccess, 0, 0, 0);
        if(!m_pMemoryMap)
            return Close(GetLastError());

        return ERROR_SUCCESS;
    }

    CMMFObject(const CMMFObject& ) { /* barrier */ }
    CMMFObject& operator = (const CMMFObject &) { return *this; /* barrier */ }

private:
    BIGINT m_FileSize;
    HANDLE m_FileHandle;
    HANDLE m_hMemoryMap;
    LPBYTE m_pMemoryMap;
    TCHAR  m_FilePath[MAX_PATH];
    bool   m_bAudoDelete;
};




간단한 사용법


CMMFObject a;
CMMFObject b;

/* a 객체는 C:\\a.map 파일을 열거나 생성하여 1024 크기로 만들고, 이름을 LOCAL_FILE 으로 지정한다.

    b 객체는 LOCAL_FILE 이름을 가진 MMF를 읽고/쓰기 모드로 연다. */
if(a.Create(_T("C:\\a.map"), _T("LOCAL_FILE"), 1024) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)a.GetPtr(), _T("까마귀날자 배떨어진다."));


if(b.Open(_T("LOCAL_FILE"), FILE_MAP_READ | FILE_MAP_WRITE) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)b.GetPtr(), _T("날아도 배 안떨어져요."));


/* a 객체는 시스템 페이지를 이용하여 1024 크기로 만들고, 이름을 SYSTEM_PAGE 으로 지정한다.

    b 객체는SYSTEM_PAGE 이름을 가진 MMF를 읽기 모드로 연다. */
if(a.Create(INVALID_HANDLE_VALUE, _T("SYSTEM_PAGE"), 1024) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)a.GetPtr(), _T("까마귀날자 배떨어진다."));


if(b.Open(_T("SYSTEM_PAGE"), FILE_MAP_READ) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)b.GetPtr(), _T("날아도 배 안떨어져요.")); <- 에러: 읽기 모드로만 열어서 쓰기 금지


CMMFObject c(a);   <- 에러: 복사 생성에 의한 다중 참조 금지

CMMFObject d = b;  <- 에러: 대입 연산에 의한 다중 참조 금지



코드를 다시 정리하면서...


1. MMF는 생성 시점에 바로 메모리에 올라가지 않는다.

     실제 생성한 MMF를 액세스 하는 시점에 해당 사용한 영역 만큼만 메모리에 올라간다.

     즉, 1 GB 짜리 MMF를 생성해도 시스템 메모리 사용량은 변함이 없고, 거기에 읽고/쓰는 영역이 생기면 그 때 변화한다.


2. 32 Bit OS에서 이론적으로 4GB까지 MMF를 생성할 수 있다고 하는데... 

     일반적으로 32 bit Windows 에서는 1.5~1.8 GB 까지 생성가능하다. 

     쫌더 쓰려면?  /3GB boot parameter 를 이용하여 2.5~2.7 GB 까지 가능하기는 하지만.. 서버용으로는 쓰기 곤란하다.

     즉, 32 Bit OS 에서는 많이 써봐야 1.8 GB 정도로 보면 된다.


3. MMF를 생성하면 메모리가 증가 하겠지만, 오픈 할 때도 증가???

     MMF를 생성하면 당연히 할당한 크기만큼 메모리가 증가한다. 

     그런데 MMF를 열면,  원래 MMF가 지정한 크기만큼 메모리가 다시 증가한다. 또 열면 또 그만큼 증가한다.


     아래의 그림을 참고하자. a는 MMF를 생성, b는 MMF를 읽기모드로 오픈한 객체 정보의 비교이다. 

     데이터에 모두 b 라는 문자열을 가졌지만.. 해당 메모리의 주소가 서로 다르다.

     MMF의 오픈이라는 의미는 생성해둔 MMF 주소를 가져다 빌려쓰는게 아닌.. 같은 크기만큼의 메모리를 만들어서

     미러형식으로 데이터의 동기화를 이루어 공유하는 것처럼 보이는 방식이다.


4. 파일을 직적 연결하여 MMF를 생성했을 때, 메모리 방식과 직접 파일 액세스 방식은 혼용하면 않된다.

     내가 직접 만든 파일로 MMF를 생성할 경우, 2가지 방식으로 액세스 할 수 있는 상태가 된다.

     하나는 직접 파일을  read/write 하는 방식과 다른 하나는 메모리를 매핑된 MMF의 주소를 이용함 메모리 방식이다.

     각각 혹은 2가지 방식을 동시에 사용할 수 있지만.. 매핑된 메모리에 쓴 내용이 바로 디스크에 반영되지 않기 때문에

     2가지 방식으로 데이터를 액세스 하면 같은 위치 영역의 디스크 데이터와  메모리 데이터가 틀어질 수 있다.


5. 그럼 파일이 빠르냐?  MMF가 빠르냐?

     MMF가 디스크에 스왑되어 있을 경우는 메모리에 올라갈 동안 지연이 일부 생기지만.. 일단 메모리에 올라간 이후라면 

     MMF가 빠르다.. 랜덤 액세스일 경우는 성능 차이가 많이 벌어진다. 

     하지만 MMF는 파일 크기를 변경할 수 없기 때문에 쓰기 작업을 이용하여 늘려가면서 쓰는것이 불가능하다.

     또한, 작업중 디스크에 스왑되기 전에 전원이 꺼진다던가 하면 작업 내용이 사라진다..  





+ Recent posts