Windows 는 프로세스가 사용할 메모리를 Heap로 관리 한다. 하나의 프로세스는 여러개의 힙들을 가질 수 있으며 프로그램은 그 힙들로 부터 메모리를 할당한다. Heap는 Windows 객체이며 메모리 할당을 하기 위해서는 핸들이 필요하다. 기본 Heap의 핸들은 다음 할수를 통해 얻을 수 있다.

  HANDLE GetProcessHeap(VOID) // 성공시 프로세스 힙의 핸들, 실패시 NULL 반환


 한 프로그램이 기본 Heap 이외의 Heap 들을 생성 하는것이 가능하며 개별 Heap를 가질때에는 다음과 같은 장점이 있다.

 1) 공평함

 2) 다중 스레드 성능 향상

 3) 할당의 효율성

 4) 할당 해제의 효율성

 5) Locality of reference에 의한 효율성


 1. Heap 생성

   새로운 Heap 를 생성하고자 하는 경우 초기 Heap의 크기를 정하여 HeapCreate 함수를 호출한다. HeapCreate 함수의 원형은 다음과 같다.

HANDLE HeapCreate(DWORD flOption, SIZE_T dwInitialSize, SIZE_T dwMaximumSize)

// 성공시 Heap 핸들 실패 시에는 NULL 반환


 초기 Heap 의 크기는 페이지 크기의 배수로 상향 조정 된다. flOption 은 HEAP_GENERATE_EXCEPTIONS / HEAP_NO_SERIALIZE / HEAP_CREATE_ENABLE_EXECUTE 등으로 설정 할수 있다.  Heap 의 최대 크기는 dwMaximumSize 로 결정된다. dwMaximumSize를 0이 아닌 값으로 설정한 경우 가상 주소 공간이 그 크기에 맞게 할당된다. 0이 아닌 값이 Heap 의 최대 크기가 된다. 0으로 설정 하는 경우 사용 가능한 가상 메모리 주소 공간에 의해 결정된다.


2. Heap 제거

 Heap를 제거 하는 경우 HeapDestory 함수를 이용한다. HeapDestory 함수의 원형은 다음과 같다.


 BOOL HeapDestory( HANDLE hHeap )


 Heap 를 통째로 해제하면 다음과 같은 장점이 있다.

 1) 자료구조 운행 코드를 작성할 필요가 없다.

 2) 개별 요소를 일일이 해제하지 않아도 된다.

 3) 한 번의 호출로 자료구조의 모든 요사가 해제되므로, 시스템이 Heap 를 관리하는데 시간을 낭비하지 않는다.


3. Heap 메모리 할당

 Heap 영역에 메모리 블록을 얻을때에는 Heap 핸들, 블록 크기, 그리고 여러 플래그들을 지정해서 HeapAlloc 함수를 호출한다.


LPVOID HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)

// 성공시 할당된 메모리 블록을 가리키는 포인터 실패시 NULL 반환


  hHeap : 할당 하고자 하는 Heap 의 핸들 값

  dwBytes : 할당할 메모리 블록의 크기


 4. Heap 메모리 해제

 Heap 영역의 메모리를 해제 할때는 HeapFree 함수를 사용한다.


 BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)


5. Heap 메모리 재 할당

 Heap 영역의 메모리 크기를 변경 하고 싶은 경우 HeapReAlloc 함수를 이용한다.


LPVOID HeapReAlloc( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes)

// 성공시 재할당된 블록을 가리키는 포인터, 실패 시에는 NULL 또는 예외가 반환


6. Heap 크기 확인

 Heap 영역의 크기를 알고 싶은 경우 HeapSize 함수를 이용한다.


SIZE_T HeapSize( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)


7. 요약

 1) CreateHeap 나 GetProcessHeap 함수를 통해 Heap 핸들을 얻는다.

 2) HeapAlloc 으로 메모리 블록들을 할당한다.

 3) HeapFree 로 개별 블록들 일부 또는 전체를 해제한다.

 4) HeapDestory 로 Heap 을 파괴하고 Heap 핸들을 닫는다.


출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Tip] 프로세스 관리  (0) 2017.12.29
[Example] 이진 검색 트리를 이용한 파일 정렬  (0) 2017.12.29
[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>
#include <process.h>

#define MAX_OPTIONS 20 
#define MAX_ARG 1000 
#define MAX_COMMAND_LINE MAX_PATH+50 
#define MAX_PATH_LONG 32767 
#define MAX_NAME 256    

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

VOID ReportError (LPCTSTR userMessage, DWORD exitCode, BOOL printErrorMessage);
VOID ReportException (LPCTSTR userMessage, DWORD exceptionCode);

int _tmain(int argc, LPTSTR argv[])
{
 HANDLE hIn = INVALID_HANDLE_VALUE, hOut = INVALID_HANDLE_VALUE;
 DWORD nXfer, iFile, j;
 CHAR outFileName[256] = {0x0, }, *pBuffer = NULL;
 OVERLAPPED ov = {0, 0, 0, 0, NULL};
 LARGE_INTEGER fSize;

 for( iFile = 1; iFile < argc; iFile++)
 {
  __try
  {
   if( _tcslen(argv[iFile]) > 250 )
   {
    ReportException(_T("The File name is Too Long"), 1);
   }

   _stprintf(outFileName, "UC_%s", argv[iFile]);

   __try
   {
    hIn = CreateFile(argv[iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

    if( hIn == INVALID_HANDLE_VALUE )
    {
     ReportException(argv[iFile], 1);
    }

    if( !GetFileSizeEx(hIn, &fSize) || fSize.HighPart > 0)
    {
     ReportException(_T("This file is to Large. \n"), 1);
    }

    hOut = CreateFile(outFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);

    if( hOut == INVALID_HANDLE_VALUE )
    {
     ReportException(outFileName, 1);
    }

    pBuffer = ( CHAR * ) malloc(fSize.LowPart);

    if( pBuffer == NULL )
     ReportException(_T("Memory allocation error \n"), 1);

    if( !ReadFile(hIn, pBuffer, fSize.LowPart, &nXfer, NULL ) || (nXfer != fSize.LowPart) )
    {
     ReportException(_T("ReadFile error \n"), 1);
    }

    for(j = 0; j < fSize.LowPart; j++)
    {
     if (isalpha(pBuffer[j]))
      pBuffer[j] = toupper(pBuffer[j]);
    }

    if( !WriteFile(hOut, pBuffer, fSize.LowPart, &nXfer, NULL) || (nXfer != fSize.LowPart))
    {
     ReportException(_T("WriteFile Error \n"), 1);
    }

   }
   __finally
   {
    if( pBuffer != NULL )
    {
     free(pBuffer);
     pBuffer = NULL;
    }

    if( hIn != INVALID_HANDLE_VALUE )
    {
     CloseHandle(hIn);
     hIn = INVALID_HANDLE_VALUE;
    }

    if( hOut != INVALID_HANDLE_VALUE )
    {
     CloseHandle(hOut);
     hOut = INVALID_HANDLE_VALUE;
    }

    _tcscpy(outFileName, _T(""));
   }
  }
  __except (EXCEPTION_EXECUTE_HANDLER)
  {
   _tprintf(_T("Error Processing File %s \n"), argv[iFile]);
   DeleteFile(outFileName);
  }
 }

 return 0;
}

VOID ReportException (LPCTSTR userMessage, DWORD exceptionCode)
{ 
 if (lstrlen (userMessage) > 0)
  ReportError (userMessage, 0, TRUE);

 if (exceptionCode != 0) 
  RaiseException (
   (0x0FFFFFFF & exceptionCode) | 0xE0000000, 0, 0, NULL);
 
 return;
}

VOID ReportError (LPCTSTR userMessage, DWORD exitCode, BOOL printErrorMessage)
{
 DWORD eMsgLen, errNum = GetLastError ();
 LPTSTR lpvSysMsg;
 _ftprintf (stderr, _T("%s\n"), userMessage);
 if (printErrorMessage) {
  eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, errNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpvSysMsg, 0, NULL);
  if (eMsgLen > 0)
  {
   _ftprintf (stderr, _T("%s\n"), lpvSysMsg);
  }
  else
  {
   _ftprintf (stderr, _T("Last Error Number; %d.\n"), errNum);
  }

  if (lpvSysMsg != NULL) LocalFree (lpvSysMsg); 
 }

 if (exitCode > 0)
  ExitProcess (exitCode);

 return;
}
​출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 이진 검색 트리를 이용한 파일 정렬  (0) 2017.12.29
[Tip] Heap Memory  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29

 Windows 의 구조적 예외 처리( Structured Exception Handling, SEH) 는 주소 접근 위반이나 산술 실패, 시스템 오류 같은 예기치 않은 비 동기적 사건에 대해 응용 프로그램이 대처할 수 있도록 하는 안정적인 메커니즘을 제공한다. 또한 SEH를 이용하면 코드 블록 안의 어느 곳에서도 프로그램을 종류할 수 있으며 그런 종료 상황에서 프로그래머가 지정한 처리 및 오류 복구가 수행되게 할수 있다. 예외 처리 구조가 없다면 NULL 포인터 참조라든가 0으로 나누기 같은 의도치 않은 예외 상황이 발생했을 때 프로그램이 즉시 종료된다. 예외 처리 절차는 다음과 같다.


 1) 예외가 발생한다. 이번 예에서는 0으로 나누기에 의한 예외가 발생했다고 가정한다.

 2) 제어권이 예외 처리부로 넘어간다. GetExceptionCode가 먼저 호출 되고, 반환값이 함수 필터의 인수가 된다.

 3) 필터 함수는 주어진 오류 코드 값에 근거해서 행동을 결정한다.

 4) 이 예에서 예외 코드는 EXCEPTION_INT_DIVIDE_BY_ZERO 이다.

 5) 필터 함수는 예외 처리부를 수행해야 한다고 결정하고, 그에 맞게 EXCEPTION_EXECUTE_HANDLER를 돌려준다.

 6) __except 절에 있는 예외 코드가 수행된다.

 7) 제어권이 __try __except 블록을 벗어난다.


출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Tip] Heap Memory  (0) 2017.12.29
[Example] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29

+ Recent posts