.net “的性能计数器”;最大自由区;?
我正在调试内存不足异常。当我得到异常时,“虚拟字节”性能计数器指示大量的可寻址空间。然而,问题是可寻址空间严重碎片化,并且“最大可用区域”(从WinDbg中的!address返回)太小 为了测量内存碎片,我想监视perfmon中的“最大可用区域”。是否有性能计数器提供此值?来源: 虚拟地址空间碎片指示器:.net “的性能计数器”;最大自由区;?,.net,windows,performance,memory,memory-management,.net,Windows,Performance,Memory,Memory Management,我正在调试内存不足异常。当我得到异常时,“虚拟字节”性能计数器指示大量的可寻址空间。然而,问题是可寻址空间严重碎片化,并且“最大可用区域”(从WinDbg中的!address返回)太小 为了测量内存碎片,我想监视perfmon中的“最大可用区域”。是否有性能计数器提供此值?来源: 虚拟地址空间碎片指示器: 总保留字节数明显大于#总提交字节数 固定对象的数量正在增加 GC句柄数正在增加 所有堆中的字节数始终在增加 我不认为这条信息只有一个性能计数器,但可以通过使用VirtualQueryExWi
- 总保留字节数明显大于#总提交字节数
- 固定对象的数量正在增加
- GC句柄数正在增加
- 所有堆中的字节数始终在增加李>
VirtualQueryEx
Win32函数来推断
您可以在最小有效虚拟地址(可从GetSystemInfo
获得)上调用它,然后可以使用返回页面范围的大小来确定要调用的下一页面范围的基址VirtualQueryEx
通过像这样反复调用VirtualQueryEx
遍历地址空间,您可以确定MEM_FREE类型的最大页面范围及其基址
这是我在“地址空间监视器”程序中使用的技术。使用我找到的代码,下面是“s”的代码示例:
公共类内存分析器{
公共长GetLargestFreeRegionSize(){
//获取最小和最大地址
系统信息系统信息;
GetSystemInfo(输出系统信息);
var procMinAddress=sysInfo.minimumApplicationAddress;
var procMaxAddress=sysInfo.maximumApplicationAddress;
//将值保存为long int,这样我以后就不必进行很多转换
var procMinAddress=(长)procMinAddress;
var procMaxAddressL=(长)procMaxAddress;
//当前进程
var process=process.GetCurrentProcess();
//以所需的访问级别打开流程
var processHandle=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ,false,PROCESS.Id);
长maxFreeRegionSize=0;
while(procMinAddressL
这些都是很好的指标,但最严重的违规者实际上是.NET之外的内存映射文件的C DLL内部。这些指示符假设问题在.NET中是可见的,但不幸的是,我的情况并非如此。如果您可以查看保留字节和提交字节,这将给您一个更好的想法。不过我没看到这样的柜台。MSN
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
}