Compteur de performance pour “la plus grande région libre”?

Je débogue une exception hors mémoire. Lorsque j’obtiens l’exception, le compteur de performance “octets virtuels” indique une quantité importante d’espace adressable. Le problème, cependant, est que l’espace adressable est très fragmenté et que la “plus grande région libre” (renvoyée par l’adresse dans WinDbg) est trop petite.

Pour mesurer la fragmentation de la mémoire, je voudrais surveiller la “plus grande région libre” de perfmon. Y a-t-il un compteur de performance qui me donne cette valeur?

Je ne crois pas qu’il existe un seul compteur de performance pour cette information, mais cela peut être déduit en utilisant la fonction VirtualQueryEx Win32.

Vous pouvez l’appeler sur l’adresse virtuelle minimale valide (qui peut être obtenue à partir de GetSystemInfo ), vous pouvez ensuite utiliser la taille de la plage de pages renvoyée pour déterminer l’adresse de base de la plage de pages suivante pour laquelle appeler VirtualQueryEx .

En parcourant l’espace adresse avec des appels répétés à VirtualQueryEx comme celui-ci, vous pouvez déterminer la plus grande plage de pages de type MEM_FREE et son adresse de base.

C’est la technique que j’ai utilisée pour mon programme “Address Space Monitor”.

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

Indicateurs de fragmentation de l’espace d’adressage virtuel:

  • Nombre total d’octets réservés nettement supérieur au nombre total d’octets engagés
  • Nombre d’objects épinglés en augmentation
  • Nombre de poignées GC en augmentation
  • Le nombre d’octets dans tous les tas augmente toujours.

En utilisant le code que j’ai trouvé ici , voici un exemple de code de la solution de 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 }