“最大的自由区域”性能计数器?

我正在debugging内存不足的exception。 当我得到exception时,“虚拟字节”性能计数器表明有足够的可寻址空间。 但是,问题是可寻址的空间是非常分散的,“最大的空闲区域”(从WinDbg中的!地址返回)太小。

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

我不相信这个信息有一个单独的性能计数器,但是可以使用VirtualQueryEx Win32函数推导出来。

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

通过重复调用VirtualQueryExVirtualQueryEx地址空间,您可以确定MEM_FREE类型的最大页面范围以及它的基地址。

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

http://dotnetdebug.ne​​t/2005/06/30/perfmon-your-debugging-buddy/

虚拟地址空间碎片指标:

  • 总保留字节数明显大于#个已提交字节数
  • 固定对象的数量增加
  • GC句柄的数量在增加
  • 所有堆中的字节数总是增加。

使用我在这里找到的代码,下面是Charles Bailey 解决方案的代码示例:

 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 }