我正在调试内存不足异常。当我得到异常时,“虚拟字节”性能计数器表明有足够的可寻址空间。然而,问题是可寻址空间严重碎片化,“最大的自由区域”(从WinDbg中的!地址返回)太小。
为了测量内存碎片,我想监视perfmon中的“最大自由区域”。是否有一个性能计数器给我这个价值?
答案 0 :(得分:2)
我不相信这条信息有一个性能计数器,但可以使用VirtualQueryEx
Win32函数推断出来。
您可以在最小有效虚拟地址(可以从GetSystemInfo
获取)上调用它,然后您可以使用返回页面范围的大小来确定下一页范围的基址。致电VirtualQueryEx
。
通过遍历地址空间并重复调用此VirtualQueryEx
,您可以确定MEM_FREE类型的最大页面范围及其基址。
这是我用于“地址空间监视器”程序的技术。
答案 1 :(得分:1)
来自http://dotnetdebug.net/2005/06/30/perfmon-your-debugging-buddy/:
虚拟地址空间碎片指标:
答案 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
}