Click here to Skip to main content
15,883,705 members
Articles / Programming Languages / C++
Article

Vitrual Memory Wrapper Class

Rate me:
Please Sign up or sign in to vote.
4.29/5 (14 votes)
11 Aug 2006CPOL3 min read 39.5K   1.3K   24   5
This article introduces a C++ wrapper class that encapsulates the details of using virtual memory.

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,        // region to reserve or commit
  SIZE_T dwSize,           // size of region
  DWORD flAllocationType,  // type of allocation
  DWORD flProtect          // type of access protection
);

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; // some number between (0 and 4K)
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);
// Only decommit (thus still reserved)

The flag MEM_RELEASE does the two things at one hit:

VirtualFree(pvBase, 0, MEM_RELEASE);
// Both decommit and 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); // Here Where It Works

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;
// First reserve max amount to be sure
// we have enough memory for our need
vMem.Reserve(MYARRAY_MAX_SIZE * (sizeof CSomeBigClass));

// some actions...

// Now we need nSize number of CSomeBigClass's
// objects; let’s commit and use it
vMem.Commit(nSize * (sizeof CSomeBigClass));
CSomeBigClass *pBigObject = (CSomeBigClass *) (PVOID) vMem;
for (int i = 0; i < nSize; i ++)
    pBigObject[i].Init();

Demo Application

Sample Image

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer 13
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Praisethanks for this idea Pin
Southmountain7-Oct-21 7:56
Southmountain7-Oct-21 7:56 
GeneralOutOfMemory Pin
Abyss26-Oct-08 7:49
Abyss26-Oct-08 7:49 
GeneralError report Pin
c2j27-Nov-06 23:14
c2j27-Nov-06 23:14 
GeneralRe: Error report Pin
Arman S.8-Nov-06 7:46
Arman S.8-Nov-06 7:46 
QuestionIs this code could be used at wince base device? Pin
DickyQi14-Aug-06 22:13
DickyQi14-Aug-06 22:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.