/// <summary> /// Enumerates regions of memory which CLR has allocated with a description of what data /// resides at that location. Note that this does not return every chunk of address space /// that CLR allocates. /// </summary> /// <returns>An enumeration of memory regions in the process.</returns> public override IEnumerable <ClrMemoryRegion> EnumerateMemoryRegions() { // Enumerate GC Segment regions. IHeapDetails[] heaps; if (ServerGC) { heaps = new IHeapDetails[HeapCount]; int i = 0; ulong[] heapList = GetServerHeapList(); if (heapList != null) { foreach (ulong addr in heapList) { heaps[i++] = GetSvrHeapDetails(addr); if (i == heaps.Length) { break; } } } else { heaps = new IHeapDetails[0]; } } else { Debug.Assert(HeapCount == 1); heaps = new IHeapDetails[1]; heaps[0] = GetWksHeapDetails(); } HashSet <ulong> addresses = new HashSet <ulong>(); for (int i = 0; i < heaps.Length; ++i) { // Small heap ISegmentData segment = GetSegmentData(heaps[i].FirstHeapSegment); while (segment != null) { Debug.Assert(segment.Start < segment.Committed); GCSegmentType type = segment.Address == heaps[i].EphemeralSegment ? GCSegmentType.Ephemeral : GCSegmentType.Regular; yield return(new MemoryRegion(this, segment.Start, segment.Committed - segment.Start, ClrMemoryRegionType.GCSegment, (uint)i, type)); if (segment.Committed <= segment.Reserved) { yield return(new MemoryRegion(this, segment.Committed, segment.Reserved - segment.Committed, ClrMemoryRegionType.ReservedGCSegment, (uint)i, type)); } if (segment.Address == segment.Next || segment.Address == 0) { break; } if (!addresses.Add(segment.Next)) { break; } segment = GetSegmentData(segment.Next); } segment = GetSegmentData(heaps[i].FirstLargeHeapSegment); while (segment != null) { Debug.Assert(segment.Start < segment.Committed); yield return(new MemoryRegion(this, segment.Start, segment.Committed - segment.Start, ClrMemoryRegionType.GCSegment, (uint)i, GCSegmentType.LargeObject)); if (segment.Committed <= segment.Reserved) { yield return(new MemoryRegion( this, segment.Committed, segment.Reserved - segment.Committed, ClrMemoryRegionType.ReservedGCSegment, (uint)i, GCSegmentType.LargeObject)); } if (segment.Address == segment.Next || segment.Address == 0) { break; } if (!addresses.Add(segment.Next)) { break; } segment = GetSegmentData(segment.Next); } } // Enumerate handle table regions. HashSet <ulong> regions = new HashSet <ulong>(); foreach (ClrHandle handle in EnumerateHandles()) { if (!_dataReader.VirtualQuery(handle.Address, out VirtualQueryData vq)) { continue; } if (regions.Contains(vq.BaseAddress)) { continue; } regions.Add(vq.BaseAddress); yield return(new MemoryRegion(this, vq.BaseAddress, vq.Size, ClrMemoryRegionType.HandleTableChunk, handle.AppDomain)); } // Enumerate each AppDomain and Module specific heap. AppDomainHeapWalker adhw = new AppDomainHeapWalker(this); IAppDomainData ad = GetAppDomainData(SystemDomainAddress); foreach (MemoryRegion region in adhw.EnumerateHeaps(ad)) { yield return(region); } foreach (ulong module in EnumerateModules(ad)) { foreach (MemoryRegion region in adhw.EnumerateModuleHeaps(ad, module)) { yield return(region); } } ad = GetAppDomainData(SharedDomainAddress); foreach (MemoryRegion region in adhw.EnumerateHeaps(ad)) { yield return(region); } foreach (ulong module in EnumerateModules(ad)) { foreach (MemoryRegion region in adhw.EnumerateModuleHeaps(ad, module)) { yield return(region); } } IAppDomainStoreData ads = GetAppDomainStoreData(); if (ads != null) { ulong[] appDomains = GetAppDomainList(ads.Count); if (appDomains != null) { foreach (ulong addr in appDomains) { ad = GetAppDomainData(addr); foreach (MemoryRegion region in adhw.EnumerateHeaps(ad)) { yield return(region); } foreach (ulong module in EnumerateModules(ad)) { foreach (MemoryRegion region in adhw.EnumerateModuleHeaps(ad, module)) { yield return(region); } } } } } // Enumerate each JIT code heap. regions.Clear(); foreach (ICodeHeap jitHeap in EnumerateJitHeaps()) { if (jitHeap.Type == CodeHeapType.Host) { if (_dataReader.VirtualQuery(jitHeap.Address, out VirtualQueryData vq)) { yield return(new MemoryRegion(this, vq.BaseAddress, vq.Size, ClrMemoryRegionType.JitHostCodeHeap)); } else { yield return(new MemoryRegion(this, jitHeap.Address, 0, ClrMemoryRegionType.JitHostCodeHeap)); } } else if (jitHeap.Type == CodeHeapType.Loader) { foreach (MemoryRegion region in adhw.EnumerateJitHeap(jitHeap.Address)) { yield return(region); } } } }
/// <summary> /// Enumerates regions of memory which CLR has allocated with a description of what data /// resides at that location. Note that this does not return every chunk of address space /// that CLR allocates. /// </summary> /// <returns>An enumeration of memory regions in the process.</returns> public override IEnumerable<ClrMemoryRegion> EnumerateMemoryRegions() { // Enumerate GC Segment regions. IHeapDetails[] heaps; if (ServerGC) { heaps = new IHeapDetails[HeapCount]; int i = 0; Address[] heapList = GetServerHeapList(); if (heapList != null) { foreach (ulong addr in heapList) { heaps[i++] = GetSvrHeapDetails(addr); if (i == heaps.Length) break; } } else { heaps = new IHeapDetails[0]; } } else { Debug.Assert(HeapCount == 1); heaps = new IHeapDetails[1]; heaps[0] = GetWksHeapDetails(); } int max = 2048; // Max number of segments in case of inconsistent data. for (int i = 0; i < heaps.Length; ++i) { // Small heap ISegmentData segment = GetSegmentData(heaps[i].FirstHeapSegment); while (segment != null && max-- > 0) { Debug.Assert(segment.Start < segment.Committed); Debug.Assert(segment.Committed <= segment.Reserved); GCSegmentType type = (segment.Address == heaps[i].EphemeralSegment) ? GCSegmentType.Ephemeral : GCSegmentType.Regular; yield return new MemoryRegion(this, segment.Start, segment.Committed - segment.Start, ClrMemoryRegionType.GCSegment, (uint)i, type); yield return new MemoryRegion(this, segment.Committed, segment.Reserved - segment.Committed, ClrMemoryRegionType.ReservedGCSegment, (uint)i, type); if (segment.Address == segment.Next || segment.Address == 0) segment = null; else segment = GetSegmentData(segment.Next); } segment = GetSegmentData(heaps[i].FirstLargeHeapSegment); while (segment != null && max-- > 0) { Debug.Assert(segment.Start < segment.Committed); Debug.Assert(segment.Committed <= segment.Reserved); yield return new MemoryRegion(this, segment.Start, segment.Committed - segment.Start, ClrMemoryRegionType.GCSegment, (uint)i, GCSegmentType.LargeObject); yield return new MemoryRegion(this, segment.Committed, segment.Reserved - segment.Committed, ClrMemoryRegionType.ReservedGCSegment, (uint)i, GCSegmentType.LargeObject); if (segment.Address == segment.Next || segment.Address == 0) segment = null; else segment = GetSegmentData(segment.Next); } } // Enumerate handle table regions. HashSet<ulong> regions = new HashSet<ulong>(); foreach (ClrHandle handle in EnumerateHandles()) { VirtualQueryData vq; if (!_dataReader.VirtualQuery(handle.Address, out vq)) continue; if (regions.Contains(vq.BaseAddress)) continue; regions.Add(vq.BaseAddress); yield return new MemoryRegion(this, vq.BaseAddress, vq.Size, ClrMemoryRegionType.HandleTableChunk, handle.AppDomain); } // Enumerate each AppDomain and Module specific heap. AppDomainHeapWalker adhw = new AppDomainHeapWalker(this); IAppDomainData ad = GetAppDomainData(SystemDomainAddress); foreach (MemoryRegion region in adhw.EnumerateHeaps(ad)) yield return region; foreach (ulong module in EnumerateModules(ad)) foreach (MemoryRegion region in adhw.EnumerateModuleHeaps(ad, module)) yield return region; ad = GetAppDomainData(SharedDomainAddress); foreach (MemoryRegion region in adhw.EnumerateHeaps(ad)) yield return region; foreach (ulong module in EnumerateModules(ad)) foreach (MemoryRegion region in adhw.EnumerateModuleHeaps(ad, module)) yield return region; IAppDomainStoreData ads = GetAppDomainStoreData(); if (ads != null) { IList<ulong> appDomains = GetAppDomainList(ads.Count); if (appDomains != null) { foreach (ulong addr in appDomains) { ad = GetAppDomainData(addr); foreach (MemoryRegion region in adhw.EnumerateHeaps(ad)) yield return region; foreach (ulong module in EnumerateModules(ad)) foreach (MemoryRegion region in adhw.EnumerateModuleHeaps(ad, module)) yield return region; } } } // Enumerate each JIT code heap. regions.Clear(); foreach (ICodeHeap jitHeap in EnumerateJitHeaps()) { if (jitHeap.Type == CodeHeapType.Host) { VirtualQueryData vq; if (_dataReader.VirtualQuery(jitHeap.Address, out vq)) yield return new MemoryRegion(this, vq.BaseAddress, vq.Size, ClrMemoryRegionType.JitHostCodeHeap); else yield return new MemoryRegion(this, jitHeap.Address, 0, ClrMemoryRegionType.JitHostCodeHeap); } else if (jitHeap.Type == CodeHeapType.Loader) { foreach (MemoryRegion region in adhw.EnumerateJitHeap(jitHeap.Address)) yield return region; } } }