Delen via


Geheugen reserveren en vastleggen

In het volgende voorbeeld ziet u het gebruik van de functies VirtualAlloc en VirtualFree bij het reserveren en doorvoeren van geheugen, indien nodig voor een dynamische matrix. Eerst wordt VirtualAlloc- aangeroepen om een blok pagina's te reserveren met NULL- opgegeven als de basisadresparameter, waardoor het systeem de locatie van het blok moet bepalen. Later wordt VirtualAlloc aangeroepen wanneer het nodig is om een pagina uit deze gereserveerde regio door te voeren en wordt het basisadres van de volgende pagina opgegeven die moet worden doorgevoerd.

In het voorbeeld wordt een gestructureerde syntaxis voor het verwerken van uitzonderingen gebruikt om pagina's uit de gereserveerde regio door te voeren. Wanneer een uitzondering op een paginafout optreedt tijdens de uitvoering van het __try blok, wordt de filterfunctie in de expressie voorafgaand aan het __except blok uitgevoerd. Als de filterfunctie een andere pagina kan toewijzen, wordt de uitvoering voortgezet in het __try blok op het punt waar de uitzondering is opgetreden. Anders wordt de foutafhandelaar uitgevoerd in het __except blok. Zie Structured Exception Handlingvoor meer informatie.

Als alternatief voor dynamische toewijzing kan het proces gewoon de hele geheugenruimte toewijzen in plaats van alleen te reserveren. Beide methoden resulteren in hetzelfde fysieke geheugengebruik omdat vastgelegde pagina's geen fysieke opslag verbruiken totdat ze voor het eerst worden geopend. Het voordeel van dynamische toewijzing is dat het totale aantal vastgelegde pagina's op het systeem wordt geminimaliseerd. Bij zeer grote toewijzingen kan het vooraf doorvoeren van een volledige toewijzing ertoe leiden dat het systeem geen doorvoerbare pagina's meer bevat, wat resulteert in fouten in de toewijzing van virtuele geheugen.

De functie ExitProcess in het __except blok brengt automatisch virtuele geheugentoewijzingen vrij. Het is dus niet nodig om de pagina's expliciet vrij te maken wanneer het programma wordt beƫindigd via dit uitvoeringspad. De functie VirtualFree maakt de gereserveerde en vastgelegde pagina's vrij als het programma is gebouwd met uitzonderingsafhandeling uitgeschakeld. Deze functie maakt gebruik van MEM_RELEASE om de gehele regio van gereserveerde en vastgelegde pagina's ongedaan te maken en vrij te geven.

In het volgende C++-voorbeeld ziet u dynamische geheugentoewijzing met behulp van een gestructureerde uitzonderingshandler.

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

}