Platform SDK: Memory

Reserving and Committing Memory

The following example illustrates the use of the VirtualAlloc and VirtualFree functions in reserving and committing memory as needed for a dynamic array. First, VirtualAlloc is called to reserve a block of pages with NULL specified as the base address parameter, forcing the system to determine the location of the block. Later, VirtualAlloc is called whenever it is necessary to commit a page from this reserved region, and the base address of the next page to be committed is specified.

The example uses structured exception-handling syntax to commit pages from the reserved region. Whenever a page fault exception occurs during the execution of the __try block, the filter function in the expression preceding the __except block is executed. If the filter function can allocate another page, execution continues in the __try block at the point where the exception occurred. Otherwise, the exception handler in the __except block is executed. For more information, see Structured Exception Handling.

As an alternative to dynamic allocation, the process can simply commit the entire region instead of only reserving it. However, committing the region consumes physical storage that might not be needed, making it unavailable for use by other processes.

The example uses VirtualFree to free the reserved and committed pages when it is finished with them. The function is called twice: first to decommit the committed pages and again to release the entire region of reserved pages.

// A short program to demonstrate dynamic memory allocation using 
// a structured exception handler. 


#include <windows.h>
#include <stdio.h>              // for printf

#define PAGELIMIT 80            // we'll ask for this many pages

LPTSTR lpNxtPage;               // address of the next page we'll ask for
DWORD dwPages = 0;              // count of pages we've gotten so far
DWORD dwPageSize;               // the 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)
    {
      printf("Exception code = %d\n", dwCode);
      return EXCEPTION_EXECUTE_HANDLER;
    }

  printf("Exception is a page fault\n");

  // If the reserved pages are used up, exit.

  if (dwPages >= PAGELIMIT)
    {
      printf("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 )
    {
      printf("VirtualAlloc failed\n");
      return EXCEPTION_EXECUTE_HANDLER;
    } else {
      printf ("Allocating another page.\n");
    }

  // Increment the page count, and advance lpNxtPage to the next page.

  dwPages++;
  lpNxtPage += dwPageSize;

  // Continue execution where the page fault occurred.

  return EXCEPTION_CONTINUE_EXECUTION;
}

VOID ErrorExit(LPTSTR oops)
{
  printf ("Error! %s with error code of %ld\n",
          oops, GetLastError ());
  exit (0);
}

VOID main(VOID)
{
  LPVOID lpvBase;               // base address of our test memory
  LPTSTR lpPtr;                 // generic character pointer
  BOOL bSuccess;                // flag
  DWORD i;                      // generic counter
  SYSTEM_INFO sSysInfo;         // useful information about the system

  GetSystemInfo(&sSysInfo);     // populate the system information structure

  printf ("This computer has a page size of %d.\n", sSysInfo.dwPageSize);

  dwPageSize = sSysInfo.dwPageSize;

  // Reserve pages in the process's virtual address space.

  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("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 is executed only if the filter function is unsuccessful
          // in committing the next page.

          ExitProcess( GetLastError() );

        }

    }


  // Release the block of pages when you are finished using them.

  bSuccess = VirtualFree(
                         lpvBase,            // base address of block
                         dwPages*dwPageSize, // bytes of committed pages
                         MEM_DECOMMIT| MEM_RELEASE); // decommit the pages

  printf ("Release was %s.\n", bSuccess ? "unsuccessful" : "successful" );
}