“最大自由区”的表现柜台?

时间:2009-01-12 23:01:00

标签: .net windows performance memory memory-management

我正在调试内存不足异常。当我得到异常时,“虚拟字节”性能计数器表明有足够的可寻址空间。然而,问题是可寻址空间严重碎片化,“最大的自由区域”(从WinDbg中的!地址返回)太小。

为了测量内存碎片,我想监视perfmon中的“最大自由区域”。是否有一个性能计数器给我这个价值?

3 个答案:

答案 0 :(得分:2)

我不相信这条信息有一个性能计数器,但可以使用VirtualQueryEx Win32函数推断出来。

您可以在最小有效虚拟地址(可以从GetSystemInfo获取)上调用它,然后您可以使用返回页面范围的大小来确定下一页范围的基址。致电VirtualQueryEx

通过遍历地址空间并重复调用此VirtualQueryEx,您可以确定MEM_FREE类型的最大页面范围及其基址。

这是我用于“地址空间监视器”程序的技术。

答案 1 :(得分:1)

来自http://dotnetdebug.net/2005/06/30/perfmon-your-debugging-buddy/

虚拟地址空间碎片指标:

  • 显着大于#total committed Bytes
  • 的总保留字节数
  • 固定对象数增加
  • GC句柄数量增加
  • 所有堆中的字节数总是在增加。

答案 2 :(得分:0)

使用我找到的代码here,这里是Charles Bailey solution的代码示例:

public class MemoryAnalyzer {
    public long GetLargestFreeRegionSize() {
        // getting minimum & maximum address
        SYSTEM_INFO sysInfo;
        GetSystemInfo(out sysInfo);

        var procMinAddress = sysInfo.minimumApplicationAddress;
        var procMaxAddress = sysInfo.maximumApplicationAddress;

        // saving the values as long ints so I won't have to do a lot of casts later
        var procMinAddressL = (long)procMinAddress;
        var procMaxAddressL = (long)procMaxAddress;

        // current process
        var process = Process.GetCurrentProcess();

        // opening the process with desired access level
        var processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ, false, process.Id);

        long maxFreeRegionSize = 0;

        while (procMinAddressL < procMaxAddressL) {
            const int memBasicInfoSize = 28; //sizeof(MEMORY_BASIC_INFORMATION)
            MEMORY_BASIC_INFORMATION memBasicInfo;
            VirtualQueryEx(processHandle, procMinAddress, out memBasicInfo, memBasicInfoSize);

            if (memBasicInfo.State == MEM_FREE) {
                maxFreeRegionSize = Math.Max(maxFreeRegionSize, memBasicInfo.RegionSize);
            }

            // move to the next memory chunk
            procMinAddressL += memBasicInfo.RegionSize;
            procMinAddress = new IntPtr(procMinAddressL);
        }

        return maxFreeRegionSize;
    }

    #region Win32
    // REQUIRED CONSTS
    const int PROCESS_QUERY_INFORMATION = 0x0400;
    const int PROCESS_WM_READ = 0x0010;
    const int MEM_FREE = 0x10000;

    // REQUIRED METHODS
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll")]
    public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

    [DllImport("kernel32.dll")]
    static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);

    // REQUIRED STRUCTS
    public struct MEMORY_BASIC_INFORMATION {
        public int BaseAddress;
        public int AllocationBase;
        public int AllocationProtect;
        public int RegionSize;
        public int State;
        public int Protect;
        public int lType;
    }

    public struct SYSTEM_INFO {
        public ushort processorArchitecture;
        ushort reserved;
        public uint pageSize;
        public IntPtr minimumApplicationAddress;
        public IntPtr maximumApplicationAddress;
        public IntPtr activeProcessorMask;
        public uint numberOfProcessors;
        public uint processorType;
        public uint allocationGranularity;
        public ushort processorLevel;
        public ushort processorRevision;
    }
    #endregion
}