Mencairkan dan Menerapkan Memori

Contoh berikut mengilustrasikan penggunaan fungsi VirtualAlloc dan VirtualFree dalam menyimpan dan menerapkan memori sesuai kebutuhan untuk array dinamis. Pertama, VirtualAlloc dipanggil untuk memesan blok halaman dengan NULL yang ditentukan sebagai parameter alamat dasar, memaksa sistem untuk menentukan lokasi blok. Kemudian, VirtualAlloc dipanggil setiap kali perlu untuk menerapkan halaman dari wilayah yang dipesan ini, dan alamat dasar halaman berikutnya yang akan diterapkan ditentukan.

Contoh menggunakan sintaks penanganan pengecualian terstruktur untuk menerapkan halaman dari wilayah yang dipesan. Setiap kali pengecualian kesalahan halaman terjadi selama eksekusi blok __try , fungsi filter dalam ekspresi sebelum blok __except dijalankan. Jika fungsi filter dapat mengalokasikan halaman lain, eksekusi berlanjut di blok __try pada titik di mana pengecualian terjadi. Jika tidak, handler pengecualian di blok __except dijalankan. Untuk informasi selengkapnya, lihat Penanganan Pengecualian Terstruktur.

Sebagai alternatif untuk alokasi dinamis, prosesnya hanya dapat melakukan seluruh wilayah alih-alih hanya menyimpannya. Kedua metode menghasilkan penggunaan memori fisik yang sama karena halaman yang diterapkan tidak menggunakan penyimpanan fisik apa pun sampai pertama kali diakses. Keuntungan dari alokasi dinamis adalah meminimalkan jumlah total halaman yang diterapkan pada sistem. Untuk alokasi yang sangat besar, pra-penerapan seluruh alokasi dapat menyebabkan sistem kehabisan halaman yang dapat diterapkan, yang mengakibatkan kegagalan alokasi memori virtual.

Fungsi ExitProcess di blok __except secara otomatis merilis alokasi memori virtual, sehingga tidak perlu secara eksplisit membebaskan halaman ketika program berakhir melalui jalur eksekusi ini. Fungsi VirtualFree membebaskan halaman yang dipesan dan diterapkan jika program dibuat dengan penanganan pengecualian dinonaktifkan. Fungsi ini menggunakan MEM_RELEASE untuk menonaktifkan dan merilis seluruh wilayah halaman yang dicadangkan dan diterapkan.

Contoh C++ berikut menunjukkan alokasi memori dinamis menggunakan handler pengecualian terstruktur.

// 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") );

}