Click here to Skip to main content
15,868,349 members
Articles / Desktop Programming / MFC

MemSpyy

Rate me:
Please Sign up or sign in to vote.
4.95/5 (9 votes)
29 Oct 2007CPOL2 min read 34.5K   791   33   2
Using OpenGL to map the virtual memory address space.

Screenshot - memspyy.jpg

Introduction

This article shows how to get a graphical memory map of the virtual address space using OpenGL. The OpenGL code itself is based on André Stein's excellent tutorial located here.

Background

Mapping the virtual address space is useful for applications that make large memory allocations. In certain cases, these allocations can fail due to memory fragmentation. By seeing the virtual address space graphically, the user can visually see the fragmentation and identify which DLLs are causing the fragmentation.

Using the code

The code itself is fairly easy to understand. It is based on the VirtualQueryEx() call, which gets information based on a process handle rather than the applications process.

The interesting work is done in the function DrawGLScene().

C++
HANDLE process = OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,false, m_PID  );

First, we get the handle to the process we want to query via the PID supplied in the edit field of the dialog box. Pretty much MFC 101.

C++
PVOID baseAddress = 0;
SIZE_T retVal = 1;
unsigned long numBlocks = 0;
while (retVal)
{
    MEMORY_BASIC_INFORMATION memBlock;
    retVal = VirtualQueryEx(process, baseAddress,&memBlock,sizeof(memBlock));

Here is the beginning of the while-loop which loops over all the address space. The idea is to call VirtualQueryEx on the lowest address, then add the size of the memory block, and call again, until it fails. That means we reached the end of the address space.

People interested in this topic might want to read Richter's book "Advanced Windows". I only have the old Win32 version, but in it, he explains using the MEMORY_BASIC_INFORMATION data structure. Specifically, he explains the differences between blocks and regions. Good background, but I found that for graphical mapping purposes, I didn't really care about that. Mapping each block was fine.

C++
if ( inSelect )
{
    glPushName( numBlocks );
    m_MemoryBlocks[numBlocks] = baseAddress;
}

This code sets up the OpenGL selection. I use the selection buffer to allow the user to mouse over any block and get information about it.

C++
glBegin(GL_LINES);
if (retVal)
{

    if (memBlock.State & MEM_FREE)
    {
        if (memBlock.RegionSize>largestFreeBlock)
            largestFreeBlock = (unsigned long) memBlock.RegionSize;

        totalFree += (unsigned long) memBlock.RegionSize;

        if ( numBlocks == m_CurrentlySelected )
            glColor3f( 1.0f, 1.0f, 1.0f );
        else
            glColor3f(m_Red,0.0f,0.0f);
        DrawMemory( memBlock.RegionSize );
    }

If we are a MEM_FREE block, then we want to draw our line in Red (unless selected, draw White).

C++
else
{
    char mappedFile[255];
    if ( GetMappedFileName( process, baseAddress, mappedFile, 255) )
    {
        totalDLL += (unsigned long) memBlock.RegionSize;

        if ( numBlocks == m_CurrentlySelected )
            glColor3f( 1.0f, 1.0f, 1.0f );
        else
            glColor3f(0.0f,1.0f,0.0f);
    }
    else
    {
        if ( numBlocks == m_CurrentlySelected )
            glColor3f( 1.0f, 1.0f, 1.0f );
        else
            glColor3f(0.0f,0.0f,m_Blue);
    }


    DrawMemory( memBlock.RegionSize );
}

If we are not free, then check to see if we are a mapped file. If so, add to 'DLL' total (although these are all mapped files, not just DLLs). Draw as Green, unless selected. Otherwise, draw as Blue. I don't explore anymore how the block is used.

C++
        baseAddress = (void *) (((char *) baseAddress) + memBlock.RegionSize);
    }
    glEnd();

    if ( inSelect )
        glPopName();

    numBlocks++;
}

Increment the base address, end the OpenGL drawing, pop the line off the selection buffer, and loop around again.

C++
CMemSpyyDlg* theParent = (CMemSpyyDlg*) GetParent();
theParent->SetLargestFree( largestFreeBlock );
theParent->SetTotalDLL( totalDLL );
theParent->SetTotalFree( totalFree );

Lastly, update the various bits of information in the dialog.

Points of interest

  • Would this have been easier with straight GDI? Ehhhh, maybe. But OpenGL is fun!
  • I also added zooming/panning. Right-click drags zooms and left-click drags pans. Double right-click resets the view.

History

  • 10/29/2007 - Initial version

License

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


Written By
Web Developer
United States United States
PJ currently works for Avid Technology, and lives in Cambridge, MA. When he isn't coding, you can find him collecting old dusty funk & soul records.

Comments and Discussions

 
GeneralEXE Pin
rrrado30-Oct-07 2:06
rrrado30-Oct-07 2:06 
GeneralRe: EXE Pin
pj453330-Oct-07 3:23
pj453330-Oct-07 3:23 

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.