メモリの予約とコミット
次の例は、動的配列に必要に応じてメモリを予約およびコミットする際に 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") );
}