Click here to Skip to main content
Click here to Skip to main content

MemSpyy

, 29 Oct 2007
Rate this:
Please Sign up or sign in to vote.
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().

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.

    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.

        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.

        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).

            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.

            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.

    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)

Share

About the Author

pj4533
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 Pinmemberrrrado30-Oct-07 2:06 
GeneralRe: EXE Pinmemberpj453330-Oct-07 3:23 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 29 Oct 2007
Article Copyright 2007 by pj4533
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid