Click Here!
home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Fast Track Visual C++ 6.0 Programming
(Publisher: John Wiley & Sons, Inc.)
Author(s): Steve Holzner
ISBN: 0471312908
Publication Date: 09/01/98

Bookmark It

Search this book:
 
Previous Table of Contents Next


There are other ways to look at memory. For example, we can use GlobalMem-oryStatus(), which returns a MEMORYSTATUS structure. This structure gives us such information as the total physical, virtual, and paging file memory.

        typedef struct _MEMORYSTATUS { // mst
            DWORD dwLength;        // sizeof(MEMORYSTATUS)
            DWORD dwMemoryLoad;    // percent of memory in use
            DWORD dwTotalPhys;     // bytes of physical memory
            DWORD dwAvailPhys;     // free physical memory bytes
            DWORD dwTotalPageFile; // bytes of paging file
            DWORD dwAvailPageFile; // free bytes of paging file
            DWORD dwTotalVirtual;  // user bytes of address space
            DWORD dwAvailVirtual;  // free user bytes
        } MEMORYSTATUS, *LPMEMORYSTATUS;

We see these functions throughout this chapter. Let’s put some to use now as we work directly with virtual and physical memory, allocating and committing it.

Using Virtual Memory

In C++ programs, programmers often content themselves with using the new operator to handle memory. However, there are times when you want to handle memory yourself—when setting up a database program, for example—and want to move and manage blocks of memory yourself.

Now that memory has gotten so big, there are new points we have to master before working with it directly. For example, you may recall that when we placed data into memory for the clipboard, we had to lock that memory while we were working with it because the Windows Memory Manager moves memory around as needed. Unfortunately, the Memory Manager that comes with Windows is not terribly efficient, which is why you might end up out of memory even though you’ve got 64MB of RAM and are only running one or two small programs. (Windows keeps a large cache of memory set aside to hold recently loaded data and code in case you want to load that data and code again, saving you the time of loading it from disk. However, when that cache fills, it can take a long time to empty.)

When we use virtual memory directly, we have to follow three steps: we allocate memory, we commit it, and, when we’re done, we free it. Allocating memory merely sets aside some of the 2GB–4MB available to us, committing it locks it into physical memory, and freeing it releases the memory for other programs to use. We start this process by taking a look at how to allocate memory.

Allocating Memory

We learn to allocate virtual memory by allocating one page of memory. Although we know that the minimum application address is 0x00400000, we can find that address ourselves with a call to GetSystemInfo(), filling a structure of type SYSTEM_INFO.

    SYSTEM_INFO SystemInfo;
    GetSystemInfo(&SystemInfo);
        .
        .
        .

We allocate the first available page. To do that, we set up two pointers: lpRequest, the location at which we are requesting memory (we start at the lowest possible user address, SystemInfo.lpMinimumApplicationAddress), and lpMemory, the pointer that returned from the virtual memory allocation function, VirtualAlloc() (if this pointer is non-NULL, we have allocated our memory):

    SYSTEM_INFO SystemInfo;
    GetSystemInfo(&SystemInfo);

    LPVOID lpRequest = SystemInfo.lpMinimumApplicationAddress;      ⇐
    LPVOID lpMemory = NULL;                                         ⇐
        .
        .
        .

Now we loop over page by page until we can allocate memory, incrementing lpRequest until lpMemory is non-NULL. We try to allocate memory by passing the location at which we want memory, the amount of memory we want (one page), and two parameters to VirtualAlloc().

    SYSTEM_INFO SystemInfo;
    GetSystemInfo(&SystemInfo);

    LPVOID lpRequest = SystemInfo.lpMinimumApplicationAddress;
    LPVOID lpMemory = NULL;

    do{
        lpMemory = VirtualAlloc(lpMemRequested, SystemInfo.dwPageSize,
MEM_RESERVE, PAGE_READWRITE);                                       ⇐

        lpRequest = (LPVOID) ((BYTE *) lpRequest+ SystemInfo.dwPageSize);
                                                                    ⇐
    }while(lpMemory == NULL);                                       ⇐

Note the two parameters we pass to VirtualAlloc() (the MEM_RESERVE parameter) reserves memory and is one of three possibilities:

MEM_COMMIT Commit physical storage
MEM_RESERVE Reserve virtual memory
MEM_TOP_DOWN Allocate memory at highest address possible

The PAGE_READWRITE parameter lets us read and write memory, and that is one of eight possible flags:

PAGE_READONLY Gives read access to the committed memory
PAGE_READWRITE Gives read and write access to committed memory
PAGE_EXECUTE Gives access to committed memory
PAGE_EXECUTE_READ Gives execute and read access to committed memory
PAGE_EXECUTE_READWRITE Gives execute, read, and write access
PAGE_GUARD Makes pages in the region guard pages
PAGE_NOACCESS Forbids access to committed memory
PAGE_NOCACHE Uses no caching in committed memory

Now that we’ve allocated virtual memory, we have to commit it to physical memory, which is either RAM or the paging file on disk.

Committing Memory

To commit the reserved memory, we use VirtualAlloc() again; this time with the MEM_COMMIT flag.

        m_lpMemCommitted = VirtualAlloc(lpMemory,
SystemInfo.dwPageSize, MEM_COMMIT, PAGE_READWRITE);

If this returns a non-NULL pointer, we’ve committed our memory. After using that memory, we release it with VirtualFree().

Deallocating Memory

The VirtualFree() function can take one of two possible flags: MEM_DECOMMIT or MEM_RELEASE. To release the memory entirely, we use MEM_RELEASE.

  VirtualFree(lpMemory, 0, MEM_RELEASE);

By following all these steps, we’ve allocated, committed, and released virtual memory, which gives us a start in memory handling. We now continue with our next program, Scanner, which will automatically scan all the memory available to us and report which code module is loaded where, giving us an idea of how to work with memory directly.

Scanning All Memory

In our next example, we use VirtualQuery() to directly examine memory and see what’s there. We scan from the lowest application address to nearly the top of memory to see what code modules are loaded where.

Create a new MDI project named Scanner and add a new item to the File menu: Scan Memory. Connect a handler function to that item, OnFileScanmemory(); when the user selects this item, we scan memory and report which module is where.

We store the display strings used in this project in the project’s document; specifically, we set aside an array of CString objects named text[] and store the number of lines of text we’ve filled in an integer, number_lines.

class CScannerDoc : public CDocument
{
protected: // create from serialization only
    CScannerDoc();
    DECLARE_DYNCREATE(CScannerDoc)

// Attributes
public:
    CString text[20];                                               ⇐
    int number_lines;                                               ⇐
    .
    .
    .


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.