Introduction
The main reason of using virtual memory is to be able to handle huge data or large memory blocks. In some cases, it is inefficient to use other kinds of memory like heaps, and in some cases, it is simply impossible to handle a big portion of data by them. Here is where we’d need to turn to virtual memory.
A Bulk of Theory
The only functions we need to use are VirtualAlloc
and VirtualFree
. VirtualAlloc
serves two purposes: reserves a block of addresses (region), and commits physical memory to the reserved region. By reserving a block, we just notify the system to keep a range of addresses ‘untouched’ such that they may (and can) be committed by real (physical) memory later. Commitment is a process when a real memory block is ‘assigned’ to a previously reserved range of addresses. This real memory can come either from primary memory (RAM) or from a paging file. A paging file is a special file, and maintained by the system itself. The purpose of a paging file is to get/pass pages from/to the primary memory. A page is a memory unit that is manipulated by the system. In Windows, the page size is 4 KB for x86, and 8 KB for Alpha and IA64.
The API Functions
As said, to allocate virtual memory, we use VirtualAlloc
(or VirtualAllocEx
). This function has the following prototype:
LPVOID VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
Actually, I will not describe the function in details but show how to use it (x86 is supposed). Assume we want to reserve a 4 KB region with read/write permissions:
DWORD dwSize = 1;
PVOID pvBase = VirtualAlloc(NULL, dwSize, MEM_RESERVE, PAGE_READWRITE);
Now, we are committing physical storage from the primary memory or from the paging file to the reserved region:
pvBase = VirtualAlloc(pvBase, -1, MEM_COMMIT, PAGE_READWRITE);
At this time, if the call succeeds, we have pvBase
as a valid pointer, and we may use it like so:
for (int j = 0; j < 1000; j ++)
pvBase[j] = j;
After the work is done, we should care for returning the committed memory back to the system (de-commit) and free the reserved regions (release). This should be done by the VirtualFree
(or VirtualFreeEx
) API function. For example:
VirtualFree(pvBase, 0, MEM_DECOMMIT);
The flag MEM_RELEASE
does the two things at one hit:
VirtualFree(pvBase, 0, MEM_RELEASE);
Wrapper Class CVMemory
I like to simplify my life if there is a chance to do it. Especially, in programming, I’m trying to create reusable classes to make programming easy when the same thing happens next time. One such thing is the CVMemory
wrapper which handles all the work of using virtual memory API functions. Its simple interface makes me think of using virtual memory more than I did before.
Here is the interface of the class:
class CVMemory
{
public:
CVMemory();
~CVMemory();
PVOID Reserve(
DWORD dwSize,
PVOID pvBaseAddr = NULL,
DWORD fdwProtect = PAGE_READWRITE);
PVOID Commit(
DWORD dwSize = -1,
PVOID pvBaseAddr = NULL,
DWORD fdwProtect = PAGE_READWRITE);
PVOID ReserveCommit(
DWORD dwSize,
PVOID pvBaseAddr = NULL,
DWORD fdwProtect = PAGE_READWRITE);
void Decommit(DWORD dwSize = -1,
PVOID pvAddress = NULL);
BOOL Release();
DWORD GetSize() const;
DWORD GetRealSize() const;
operator PVOID ();
PVOID GetBase();
};
First, note that the destructor frees everything (I mean de-commits and releases) for us. Another noticeable thing is the defined PVOID()
operator; this helps us with passing a CVMemory
object where PVOID
is expected, like so:
extern void func(PVOID pv);
CVMemory vMem;
func(vMem);
Other useful methods are GetSize
and GetRealSize
. The former shows how much we requested to reserve, and the latter shows how much we really got.
How To Use
Suppose we want to reserve memory for an array of big objects of type CSomeBigClass
. We may use CVMemory
in the following way:
CVMemory vMem;
vMem.Reserve(MYARRAY_MAX_SIZE * (sizeof CSomeBigClass));
vMem.Commit(nSize * (sizeof CSomeBigClass));
CSomeBigClass *pBigObject = (CSomeBigClass *) (PVOID) vMem;
for (int i = 0; i < nSize; i ++)
pBigObject[i].Init();
Demo Application

The demo uses the CVMemory
class to show how much virtual memory can be used (reserved and committed) on a machine it runs on. You may look at its code to see how CVMemory
is used. Also, it would be interesting to see how the demo uses a binary search algorithm to find the wanted result.