static void AddGcRegion(long baseAddr, long regionSize) { long startAddr = baseAddr; long endAddr = baseAddr + regionSize; GcRegion gcRegion; for (gcRegion = gcRegionList; gcRegion != null; gcRegion = gcRegion.next) { if (gcRegion.startAddr <= startAddr && gcRegion.endAddr >= endAddr) { // the new region is a subset of an old one - ignore it. return; } else if (startAddr <= gcRegion.startAddr && endAddr >= gcRegion.endAddr) { // an existing region is a subset of the new one - enlarge the existing one. gcRegion.startAddr = startAddr; gcRegion.endAddr = endAddr; return; } } gcRegion = new GcRegion(); gcRegion.next = gcRegionList; gcRegionList = gcRegion; gcRegion.startAddr = endAddr; gcRegion.endAddr = endAddr; }
internal static bool PageInGcRegion(IntPtr addr) { long lAddr = (long)addr; for (GcRegion gcRegion = gcRegionList; gcRegion != null; gcRegion = gcRegion.next) { if (lAddr >= gcRegion.startAddr && lAddr < gcRegion.endAddr) { return(true); } } return(false); }
internal static void InitGcRegions(IntPtr hProcess) { gcRegionList = null; MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); IntPtr addr = IntPtr.Zero; while (true) { if (VirtualQueryEx(hProcess, addr, out mbi, System.Runtime.InteropServices.Marshal.SizeOf(mbi)) <= 0) { break; } if (mbi.State != 0x10000 && mbi.Type == 0x20000 && (long)mbi.BaseAddress - (long)mbi.AllocationBase + mbi.RegionSize >= 16 * 1024 * 1024) { AddGcRegion((long)mbi.AllocationBase, mbi.RegionSize); } addr = (IntPtr)((long)mbi.BaseAddress + mbi.RegionSize); } }
static void RunVadump(Process p) { ProcessStartInfo processStartInfo = new ProcessStartInfo("vadump.exe"); processStartInfo.Arguments = "-o -p " + p.Id; processStartInfo.UseShellExecute = false; processStartInfo.RedirectStandardOutput = true; Process vadumpProcess = Process.Start(processStartInfo); // vadumpProcess.WaitForExit(); IntPtr processHandle = OpenProcess(0x1F0FFF, false, p.Id); GcRegion.InitGcRegions(processHandle); StreamReader r = vadumpProcess.StandardOutput; string line; MemoryCategory.categoryList = null; while ((line = r.ReadLine()) != null) { string[] fields = line.Split(' '); if (fields.Length >= 3 && fields[0].IndexOf("0x") == 0 && fields[1].Length >= 3 && fields[1][0] == '(') { bool privatePage = fields[1] == "(0)"; switch (fields[2]) { case "PRIVATE": IntPtr addr = (IntPtr)Int64.Parse(fields[0].Substring(2), NumberStyles.HexNumber); if (GcRegion.PageInGcRegion(addr)) { MemoryCategory.AddPage("Heaps", "GC Heap", privatePage); } else { MemoryCategory.AddPage("Heaps", "Private VirtualAlloc", privatePage); } break; case "Stack": string thread = null; if (fields.Length >= 6 && fields[4] == "ThreadID") { thread = fields[4] + " " + fields[5]; } MemoryCategory.AddPage("Stacks", thread, privatePage); break; case "Process": MemoryCategory.AddPage("Heaps", "Process Heap", privatePage); break; case "UNKNOWN_MAPPED": MemoryCategory.AddPage("Other Stuff", "Unknown Mapped", privatePage); break; case "DATAFILE_MAPPED": string fileName = "<Unknown>"; if (fields.Length == 6) { fileName = fields[5]; } MemoryCategory.AddPage("Mapped data", fileName, privatePage); break; case "Private": MemoryCategory.AddPage("Heaps", "Private Heaps", privatePage); break; case "TEB": MemoryCategory.AddPage("Other Stuff", "TEB", privatePage); break; default: MemoryCategory.AddPage("Modules", fields[2], privatePage); break; } } else if (fields.Length >= 2 && fields[0].IndexOf("0xc") == 0 && fields[1] == "->") { MemoryCategory.AddPage("Other Stuff", "Page Tables", true); } } MemoryCategory.PrintCategories(); }