private static MemoryNode Root() { var ret = new MemoryNode(); ret.info.RegionSize = unchecked (new IntPtr((long)ulong.MaxValue)); ret.Name = "[ROOT]"; return(ret); }
private void Insert(MemoryNode newNode) { Debug.Assert(Address <= newNode.Address && newNode.End <= End); if (Children == null) { Children = new List <MemoryNode>(); } // Search backwards for efficiency. for (int i = Children.Count; 0 < i;) { var child = Children[--i]; if (child.Address <= newNode.Address && newNode.End <= child.End) { child.Insert(newNode); return; } } Children.Add(newNode); newNode.Parent = this; }
/// <summary> /// This is the main entry point into the MemoryNode class. Basically giving a process ID return /// a MemoryNode that represents the roll-up of all memory in the process. /// </summary> public unsafe static MemoryNode MemorySnapShotForProcess(int processID) { var root = Root(); var process = Process.GetProcessById(processID); bool is32BitProcess = false; NativeMethods.IsWow64Process(process.Handle, out is32BitProcess); var kernelToUser = new KernelToUserDriveMapping(); var name = new StringBuilder(260); long MaxAddress = 0x7fffffff; long address = 0; do { var child = new MemoryNode(); int result = NativeMethods.VirtualQueryEx(process.Handle, (IntPtr)address, out child.info, (uint)Marshal.SizeOf(child.info)); address = (long)child.info.BaseAddress + (long)child.info.RegionSize; // TODO FIX NOW worry about error codes. if (result == 0) { break; } if (child.info.Type == NativeMethods.MemoryType.MEM_IMAGE || child.info.Type == NativeMethods.MemoryType.MEM_MAPPED) { name.Clear(); var ret = NativeMethods.GetMappedFileName(process.Handle, (IntPtr)address, name, name.Capacity); if (ret != 0) { var kernelName = name.ToString(); child.Name = kernelToUser[kernelName]; } else { Debug.WriteLine("Error, GetMappedFileName failed."); } } root.Insert(child); } while (address <= MaxAddress); NativeMethods.PSAPI_WORKING_SET_INFORMATION *WSInfo = stackalloc NativeMethods.PSAPI_WORKING_SET_INFORMATION[1]; NativeMethods.QueryWorkingSet(process.Handle, WSInfo, sizeof(NativeMethods.PSAPI_WORKING_SET_INFORMATION)); int buffSize = (int)(WSInfo->NumberOfEntries) * 8 + 8 + 1024; // The 1024 is to allow for working set growth WSInfo = (NativeMethods.PSAPI_WORKING_SET_INFORMATION *)Marshal.AllocHGlobal(buffSize); if (!NativeMethods.QueryWorkingSet(process.Handle, WSInfo, buffSize)) { Marshal.FreeHGlobal((IntPtr)WSInfo); Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error()); } // Copy the working set info to an array and sort the page addresses. int numBlocks = (int)WSInfo->NumberOfEntries; ulong[] blocks = new ulong[numBlocks]; for (var curWSIdx = 0; curWSIdx < numBlocks; curWSIdx++) { blocks[curWSIdx] = WSInfo->WorkingSetInfo(curWSIdx).Address; } Array.Sort(blocks); Marshal.FreeHGlobal((IntPtr)WSInfo); // Attribute the working set to the regions of memory int curPageIdx = 0; foreach (var region in root.Children) { var end = region.End; while (curPageIdx < blocks.Length && blocks[curPageIdx] < end) { curPageIdx++; region.PrivateWorkingSet += 4; // TODO FIX NOW } } GC.KeepAlive(process); return(root); }