Click here to Skip to main content
12,824,299 members (40,982 online)
Click here to Skip to main content

Tagged as


18 bookmarked
Posted 24 Nov 2011

Mnemonic: Assisting Your (virtual) Memory

, 9 Feb 2012 CPOL
A tool for visualizing the virtual memory used by Windows processes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.ComponentModel;

namespace Mnemonic
    public class VMRegionInfo
        public UIntPtr regionStartAddress;
        public UInt64 regionSize;
        public string regionName;

        public bool ContainsAddress(UIntPtr address)
                ((UInt64)regionStartAddress <= (UInt64)address) &&
                ((UInt64)regionEndAddress >= (UInt64)address);

        public UIntPtr regionEndAddress
            get { return UIntPtr.Add(regionStartAddress, (int)(regionSize - 1)); }

    public class VMChunkInfo : VMRegionInfo
        public PageState state;
        public PageType type;

    public enum PageState
        Committed = 0x1000,
        Free = 0x10000,
        Reserved = 0x2000

    public enum PageType
        Image = 0x01000000,     // Mapped into the view of an image section
        Mapped = 0x00040000,    // Mapped into the view of a section
        Private = 0x00020000    // Private (not shared with other processes)

    static class ProcessExtensions
        [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWow64Process([In] IntPtr processHandle, [Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process);

        public static bool Is64BitProcess(this Process process)
            if (!Environment.Is64BitOperatingSystem)
                return false;

            bool isWow64Process;
            if (!IsWow64Process(process.Handle, out isWow64Process))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            return !isWow64Process;


    class VirtualMemoryScanner
#region P/Invoke
        public struct MEMORY_BASIC_INFORMATION
            public UIntPtr BaseAddress;
            public UIntPtr AllocationBase;
            public uint AllocationProtect;
            public UIntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;

        static extern int VirtualQueryEx(IntPtr hProcess, UIntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);

        public struct SYSTEM_INFO
            public uint dwOemId;
            public uint dwPageSize;
            public uint lpMinimumApplicationAddress;
            public uint lpMaximumApplicationAddress;
            public uint dwActiveProcessorMask;
            public uint dwNumberOfProcessors;
            public uint dwProcessorType;
            public uint dwAllocationGranularity;
            public uint dwProcessorLevel;
            public uint dwProcessorRevision;

        static extern void GetSystemInfo(ref SYSTEM_INFO pSI);

        [DllImport("psapi.dll", SetLastError = true)]
        public static extern uint GetMappedFileName(IntPtr m_hProcess, UIntPtr lpv, StringBuilder
                lpFilename, uint nSize);

        public static string GetMappedFileName(IntPtr process, UIntPtr address)
            StringBuilder fn = new StringBuilder(250);
            if (GetMappedFileName(process, address, fn, 250) > 0)
                return fn.ToString();
                return string.Empty;

        public static uint PageSize
                SYSTEM_INFO pSI = new SYSTEM_INFO();
                GetSystemInfo(ref pSI);
                return pSI.dwPageSize;

        public static uint AllocationGranularity
                SYSTEM_INFO pSI = new SYSTEM_INFO();
                GetSystemInfo(ref pSI);
                return pSI.dwAllocationGranularity;


        public Process process { get; set; }

        public VirtualMemoryScanner()

        public void Scan(Process process, out List<VMChunkInfo> chunkInfos, out List<VMRegionInfo> mappingInfos, out UIntPtr addressLimit)
            this.process = process;
            IntPtr processHandle = process.Handle;

            chunkInfos = new List<VMChunkInfo>();

            const UInt64 GB = 1024 * 1024 * 1024;
            UInt64 maxRegionSize = (UInt64)2 * GB;

            UIntPtr memoryLimit;
            if (process.Is64BitProcess())
                memoryLimit = (UIntPtr)((UInt64)6 * GB);
                memoryLimit = UIntPtr.Subtract(UIntPtr.Zero, 1);

            addressLimit = memoryLimit;

            // Use UIntPtr so that we can cope with addresses above 2GB in a /3GB or "4GT" environment, or 64-bit Windows
            UIntPtr address = (UIntPtr)0;
            while ((UInt64)address < (UInt64)memoryLimit)
                int result = VirtualQueryEx(processHandle, address, out m, (uint)Marshal.SizeOf(m));
                if (0 == result || (UInt64)m.RegionSize > maxRegionSize)
                    // Record the 'end' of the address scale
                    // (Expect 2GB in the case of a Win32 process running under 32-bit Windows, but may be
                    // extended to up to 3GB if the OS is configured for "4 GT tuning" with the /3GB switch
                    // Expect 4GB in the case of a Win32 process running under 64-bit Windows)
                    addressLimit = address;

                VMChunkInfo chunk = new VMChunkInfo();
                chunk.regionStartAddress = (UIntPtr)(UInt64)m.BaseAddress;
                chunk.regionSize = (UInt64)m.RegionSize;
                chunk.type = (PageType)m.Type;
                chunk.state = (PageState)m.State;

                if ((chunk.type == PageType.Image) || (chunk.type == PageType.Mapped))
                    // .Net 4 maps assemblies into memory using the memory-mapped file mechanism;
                    // they don't show up in Process.Modules list
                    string fileName = GetMappedFileName(processHandle, chunk.regionStartAddress);
                    if (fileName.Length > 0)
                        fileName = Path.GetFileName(fileName);
                        chunk.regionName = fileName;


                UIntPtr oldAddress = address;
                // It's maddening, but UIntPtr.Add can't cope with 64-bit offsets under Win64!
                address = UIntPtr.Add(address, (int)m.RegionSize);
                if ((UInt64)address <= (UInt64)oldAddress)
                    addressLimit = oldAddress;

            mappingInfos = new List<VMRegionInfo>();
                foreach (ProcessModule module in process.Modules)
                    VMRegionInfo mappingInfo = new VMRegionInfo();

                    mappingInfo.regionStartAddress = (UIntPtr)(UInt64)module.BaseAddress;
                    mappingInfo.regionSize = (UInt64)module.ModuleMemorySize;
                    mappingInfo.regionName = Path.GetFileName(module.FileName);

            catch { }

            // Sort by address
            mappingInfos.Sort(delegate(VMRegionInfo map1, VMRegionInfo map2)
                return Comparer<UInt64>.Default.Compare((UInt64)map1.regionStartAddress, (UInt64)map2.regionStartAddress);

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


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


About the Author

Phil Atkin
Founder Pixel Analytics Ltd.
United Kingdom United Kingdom
My expertise is concentrated on image processing and analysis; I've been doing it most of my working life. Now I offer consultancy through my own company, as well as developing software products.

You may also be interested in...

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170308.1 | Last Updated 9 Feb 2012
Article Copyright 2011 by Phil Atkin
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid