메모리 예약 및 커밋
다음 예제에서는 동적 배열에 필요한 메모리를 예약하고 커밋하는 데 VirtualAlloc 및 VirtualFree 함수를 사용하는 것을 보여 줍니다. 먼저 VirtualAlloc 이 호출되어 NULL 이 기본 주소 매개 변수로 지정된 페이지 블록을 예약하여 시스템이 블록의 위치를 결정하도록 합니다. 나중에 이 예약된 지역에서 페이지를 커밋해야 할 때마다 VirtualAlloc 이 호출되고 커밋할 다음 페이지의 기본 주소가 지정됩니다.
이 예제에서는 구조적 예외 처리 구문을 사용하여 예약된 지역의 페이지를 커밋합니다. __try 블록을 실행하는 동안 페이지 오류 예외가 발생할 때마다 __except 블록 앞의 식에서 필터 함수가 실행됩니다. 필터 함수가 다른 페이지를 할당할 수 있는 경우 예외가 발생한 지점에서 __try 블록에서 실행이 계속됩니다. 그렇지 않으면 __except 블록의 예외 처리기가 실행됩니다. 자세한 내용은 구조적 예외 처리를 참조하세요.
동적 할당 대신 프로세스는 예약만 하는 대신 전체 지역을 커밋할 수 있습니다. 커밋된 페이지는 처음 액세스할 때까지 실제 스토리지를 사용하지 않기 때문에 두 방법 모두 동일한 실제 메모리 사용량을 초래합니다. 동적 할당의 장점은 시스템에서 커밋된 페이지의 총 수를 최소화한다는 것입니다. 매우 큰 할당의 경우 전체 할당을 미리 커밋하면 시스템에서 커밋 가능한 페이지가 부족하여 가상 메모리 할당이 실패할 수 있습니다.
__except 블록의 ExitProcess 함수는 가상 메모리 할당을 자동으로 해제하므로 프로그램이 이 실행 경로를 통해 종료될 때 페이지를 명시적으로 해제할 필요가 없습니다. 프로그램이 예외 처리를 사용하지 않도록 설정하여 빌드된 경우 VirtualFree 함수는 예약된 페이지와 커밋된 페이지를 해제합니다. 이 함수는 MEM_RELEASE 사용하여 예약된 페이지와 커밋된 페이지의 전체 영역을 커밋 해제하고 해제합니다.
다음 C++ 예제에서는 구조적 예외 처리기를 사용하여 동적 메모리 할당을 보여 줍니다.
// A short program to demonstrate dynamic memory allocation
// using a structured exception handler.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h> // For exit
#define PAGELIMIT 80 // Number of pages to ask for
LPTSTR lpNxtPage; // Address of the next page to ask for
DWORD dwPages = 0; // Count of pages gotten so far
DWORD dwPageSize; // Page size on this computer
INT PageFaultExceptionFilter(DWORD dwCode)
{
LPVOID lpvResult;
// If the exception is not a page fault, exit.
if (dwCode != EXCEPTION_ACCESS_VIOLATION)
{
_tprintf(TEXT("Exception code = %d.\n"), dwCode);
return EXCEPTION_EXECUTE_HANDLER;
}
_tprintf(TEXT("Exception is a page fault.\n"));
// If the reserved pages are used up, exit.
if (dwPages >= PAGELIMIT)
{
_tprintf(TEXT("Exception: out of pages.\n"));
return EXCEPTION_EXECUTE_HANDLER;
}
// Otherwise, commit another page.
lpvResult = VirtualAlloc(
(LPVOID) lpNxtPage, // Next page to commit
dwPageSize, // Page size, in bytes
MEM_COMMIT, // Allocate a committed page
PAGE_READWRITE); // Read/write access
if (lpvResult == NULL )
{
_tprintf(TEXT("VirtualAlloc failed.\n"));
return EXCEPTION_EXECUTE_HANDLER;
}
else
{
_tprintf(TEXT("Allocating another page.\n"));
}
// Increment the page count, and advance lpNxtPage to the next page.
dwPages++;
lpNxtPage = (LPTSTR) ((PCHAR) lpNxtPage + dwPageSize);
// Continue execution where the page fault occurred.
return EXCEPTION_CONTINUE_EXECUTION;
}
VOID ErrorExit(LPTSTR lpMsg)
{
_tprintf(TEXT("Error! %s with error code of %ld.\n"),
lpMsg, GetLastError ());
exit (0);
}
VOID _tmain(VOID)
{
LPVOID lpvBase; // Base address of the test memory
LPTSTR lpPtr; // Generic character pointer
BOOL bSuccess; // Flag
DWORD i; // Generic counter
SYSTEM_INFO sSysInfo; // Useful information about the system
GetSystemInfo(&sSysInfo); // Initialize the structure.
_tprintf (TEXT("This computer has page size %d.\n"), sSysInfo.dwPageSize);
dwPageSize = sSysInfo.dwPageSize;
// Reserve pages in the virtual address space of the process.
lpvBase = VirtualAlloc(
NULL, // System selects address
PAGELIMIT*dwPageSize, // Size of allocation
MEM_RESERVE, // Allocate reserved pages
PAGE_NOACCESS); // Protection = no access
if (lpvBase == NULL )
ErrorExit(TEXT("VirtualAlloc reserve failed."));
lpPtr = lpNxtPage = (LPTSTR) lpvBase;
// Use structured exception handling when accessing the pages.
// If a page fault occurs, the exception filter is executed to
// commit another page from the reserved block of pages.
for (i=0; i < PAGELIMIT*dwPageSize; i++)
{
__try
{
// Write to memory.
lpPtr[i] = 'a';
}
// If there's a page fault, commit another page and try again.
__except ( PageFaultExceptionFilter( GetExceptionCode() ) )
{
// This code is executed only if the filter function
// is unsuccessful in committing the next page.
_tprintf (TEXT("Exiting process.\n"));
ExitProcess( GetLastError() );
}
}
// Release the block of pages when you are finished using them.
bSuccess = VirtualFree(
lpvBase, // Base address of block
0, // Bytes of committed pages
MEM_RELEASE); // Decommit the pages
_tprintf (TEXT("Release %s.\n"), bSuccess ? TEXT("succeeded") : TEXT("failed") );
}