From 4c9c8acc22d8d9b2e4e5212a3c6b584d26a557aa Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Tue, 4 Apr 2023 12:37:05 -0700 Subject: [PATCH 1/3] Fix IndexOutOfRangeException (#3800) * Fix IndexOutOfRangeException Fix an IndexOutOfRangeException with !sos maddress. * Add initial parts length check * One more fix --- ...MemoryRegionServiceFromDebuggerServices.cs | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs b/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs index 7b60998623..15c729c1df 100644 --- a/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs @@ -56,16 +56,28 @@ public IEnumerable EnumerateRegions() else { string[] parts = ((line[0] == '+') ? line.Substring(1) : line).Split(new char[] { ' ' }, 6, StringSplitOptions.RemoveEmptyEntries); - ulong start = ulong.Parse(parts[0].Replace("`", ""), System.Globalization.NumberStyles.HexNumber); - ulong end = ulong.Parse(parts[1].Replace("`", ""), System.Globalization.NumberStyles.HexNumber); + if (parts.Length < 2) + { + continue; + } + + if (!ulong.TryParse(parts[0].Replace("`", ""), System.Globalization.NumberStyles.HexNumber, null, out ulong start)) + { + continue; + } + + if (!ulong.TryParse(parts[1].Replace("`", ""), System.Globalization.NumberStyles.HexNumber, null, out ulong end)) + { + continue; + } int index = 3; - if (Enum.TryParse(parts[index], ignoreCase: true, out MemoryRegionType type)) + if (GetEnumValue(parts, index, out MemoryRegionType type)) { index++; } - if (Enum.TryParse(parts[index], ignoreCase: true, out MemoryRegionState state)) + if (GetEnumValue(parts, index, out MemoryRegionState state)) { index++; } @@ -103,7 +115,7 @@ public IEnumerable EnumerateRegions() index++; } - string description = parts[index++].Trim(); + string description = index < parts.Length ? parts[index++].Trim() : ""; // On Linux, !address is reporting this as MEM_PRIVATE or MEM_UNKNOWN if (description == "Image") @@ -119,7 +131,7 @@ public IEnumerable EnumerateRegions() } string image = null; - if (type == MemoryRegionType.MEM_IMAGE) + if (type == MemoryRegionType.MEM_IMAGE && index < parts.Length) { image = parts[index].Substring(1, parts[index].Length - 2); index++; @@ -187,6 +199,18 @@ public IEnumerable EnumerateRegions() } } + private static bool GetEnumValue(string[] parts, int index, out T type) + where T : struct + { + if (index < parts.Length) + { + return Enum.TryParse(parts[index], ignoreCase: true, out type); + } + + type = default; + return false; + } + private (int hresult, string output) RunCommandWithOutput(string command) { using DbgEngOutputHolder dbgengOutput = new(_client); From ed23a7591a8d18999c868deb5d5c40eb6234d64e Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Thu, 6 Apr 2023 17:21:23 -0700 Subject: [PATCH 2/3] Update ClrMD version (#3804) I moved the the "Generation" enum to ClrMD itself. It's far more useful (and accurate) to talk about an object's generation as a member of an enum which describes it rather than a simple integer. This change flowed through the SOS commands which used ClrSegment.GetGeneration. I manually tested all commands affected. --- eng/Version.Details.xml | 8 ++-- eng/Versions.props | 2 +- .../ExtensionMethodHelpers.cs | 34 -------------- .../FindEphemeralReferencesToLOHCommand.cs | 21 ++++++--- .../FindReferencesToEphemeralCommand.cs | 13 +++--- .../GCHeapStatCommand.cs | 45 ++++++++++++------- .../GCWhereCommand.cs | 24 +++++----- .../Generation.cs | 16 ------- .../SizeStatsCommand.cs | 22 ++++----- 9 files changed, 76 insertions(+), 109 deletions(-) delete mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7f8369c2f7..6950b9c51c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore e09f81a0b38786cb20f66b589a8b88b6997a62da - + https://github.com/microsoft/clrmd - e61e6bdb23739ad2c59616b6c8d6659f4558c88d + 3368bf4451a9441076595022fdff0f2bbea57b1b - + https://github.com/microsoft/clrmd - e61e6bdb23739ad2c59616b6c8d6659f4558c88d + 3368bf4451a9441076595022fdff0f2bbea57b1b diff --git a/eng/Versions.props b/eng/Versions.props index a011db18ae..b513c48f5d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 1.1.0 - 3.0.0-beta.23177.1 + 3.0.0-beta.23205.1 16.9.0-beta1.21055.5 3.0.7 diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs index 15f81d59ff..5f35b39381 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs @@ -37,39 +37,5 @@ internal static ulong FindMostCommonPointer(this IEnumerable enumerable) group ptr by ptr into g orderby g.Count() descending select g.First()).First(); - - internal static Generation GetGeneration(this ClrObject obj, ClrSegment knownSegment) - { - if (knownSegment is null) - { - knownSegment = obj.Type.Heap.GetSegmentByAddress(obj); - if (knownSegment is null) - { - return Generation.Error; - } - } - - if (knownSegment.Kind == GCSegmentKind.Ephemeral) - { - return knownSegment.GetGeneration(obj) switch - { - 0 => Generation.Gen0, - 1 => Generation.Gen1, - 2 => Generation.Gen2, - _ => Generation.Error - }; - } - - return knownSegment.Kind switch - { - GCSegmentKind.Generation0 => Generation.Gen0, - GCSegmentKind.Generation1 => Generation.Gen1, - GCSegmentKind.Generation2 => Generation.Gen2, - GCSegmentKind.Large => Generation.Large, - GCSegmentKind.Pinned => Generation.Pinned, - GCSegmentKind.Frozen => Generation.Frozen, - _ => Generation.Error - }; - } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs index d28166badb..c7fa399b83 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs @@ -130,8 +130,8 @@ public override void Invoke() Console.CancellationToken.ThrowIfCancellationRequested(); // This handles both regions and segments - Generation gen = obj.GetGeneration(seg); - if (gen is not Generation.Gen0 or Generation.Gen1) + Generation gen = seg.GetGeneration(obj); + if (gen is not Generation.Generation0 or Generation.Generation1) { continue; } @@ -145,8 +145,7 @@ public override void Invoke() continue; } - Generation refGen = objRef.GetGeneration(null); - if (refGen == Generation.Large) + if (GetGenerationWithoutSegment(objRef) == Generation.Large) { yield return (obj, objRef); } @@ -174,8 +173,7 @@ public override void Invoke() continue; } - Generation refGen = objRef.GetGeneration(null); - if (refGen is Generation.Gen0 or Generation.Gen1) + if (GetGenerationWithoutSegment(objRef) is Generation.Generation0 or Generation.Generation1) { yield return (obj, objRef); } @@ -183,5 +181,16 @@ public override void Invoke() } } } + + private Generation GetGenerationWithoutSegment(ClrObject obj) + { + ClrSegment seg = Runtime.Heap.GetSegmentByAddress(obj); + if (seg is not null) + { + return seg.GetGeneration(obj); + } + + return Generation.Unknown; + } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs index e77660dbd1..8c5f3c0eac 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs @@ -88,8 +88,8 @@ private IEnumerable FindObjectsWithEphemeralReferences() Console.CancellationToken.ThrowIfCancellationRequested(); // Skip this object if it's gen0 or we hit an error - Generation objGen = obj.GetGeneration(seg); - if (objGen is Generation.Gen0 or Generation.Error) + Generation objGen = seg.GetGeneration(obj); + if (objGen is Generation.Generation0 or Generation.Unknown) { continue; } @@ -108,10 +108,11 @@ private IEnumerable FindObjectsWithEphemeralReferences() ulong refObjSize = objRef.Size; - Generation refGen = objRef.GetGeneration(null); + ClrSegment refSeg = Runtime.Heap.GetSegmentByAddress(objRef); + Generation refGen = refSeg?.GetGeneration(objRef) ?? Generation.Unknown; switch (refGen) { - case Generation.Gen0: + case Generation.Generation0: gen0 ??= new EphemeralRefCount() { Object = obj, @@ -128,8 +129,8 @@ private IEnumerable FindObjectsWithEphemeralReferences() break; - case Generation.Gen1: - if (objGen > Generation.Gen1) + case Generation.Generation1: + if (objGen > Generation.Generation1) { gen1 ??= new EphemeralRefCount() { diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs index 062eb694b9..a7c24db50a 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs @@ -217,25 +217,22 @@ private HeapInfo GetHeapInfo(ClrSubHeap heap) continue; } - GenerationInfo gen = seg.GetGeneration(obj) switch + GenerationInfo genInfo = result.GetInfoByGeneration(seg.GetGeneration(obj)); + if (genInfo is not null) { - 0 => result.Gen0, - 1 => result.Gen1, - _ => result.Gen2, - }; - - if (obj.IsFree) - { - result.Ephemeral.Free += obj.Size; - gen.Free += obj.Size; - } - else - { - gen.Allocated += obj.Size; - - if (IncludeUnreachable && !LiveObjects.IsLive(obj)) + if (obj.IsFree) + { + result.Ephemeral.Free += obj.Size; + genInfo.Free += obj.Size; + } + else { - gen.Unrooted += obj.Size; + genInfo.Allocated += obj.Size; + + if (IncludeUnreachable && !LiveObjects.IsLive(obj)) + { + genInfo.Unrooted += obj.Size; + } } } } @@ -307,6 +304,20 @@ private sealed class HeapInfo Frozen = left.Frozen + right.Frozen, }; } + + public GenerationInfo GetInfoByGeneration(Generation gen) + { + return gen switch + { + Generation.Generation0 => Gen0, + Generation.Generation1 => Gen1, + Generation.Generation2 => Gen2, + Generation.Large => LoH, + Generation.Pinned => PoH, + Generation.Frozen => Frozen, + _ => null + }; + } } private sealed class GenerationInfo diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs index 3967c4bb32..fad8d35df1 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs @@ -54,22 +54,18 @@ public override void Invoke() { generation = "reserve"; } - else if (segment.Kind == GCSegmentKind.Frozen) - { - generation = "frozen"; - } - else if (segment.Kind == GCSegmentKind.Pinned) - { - generation = "pinned"; - } - else if (segment.Kind == GCSegmentKind.Large) - { - generation = "large"; - } else { - int gen = segment.GetGeneration(address); - generation = gen != -1 ? gen.ToString() : "???"; + generation = segment.GetGeneration(address) switch + { + Generation.Generation0 => "0", + Generation.Generation1 => "1", + Generation.Generation2 => "2", + Generation.Frozen => "frozen", + Generation.Pinned => "pinned", + Generation.Large => "large", + _ => "???", + }; } object addressColumn = segment.ObjectRange.Contains(address) ? new DmlListNearObj(address) : address; diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs deleted file mode 100644 index 990ef71a2d..0000000000 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.Diagnostics.ExtensionCommands -{ - internal enum Generation - { - Gen0, - Gen1, - Gen2, - Large, - Pinned, - Frozen, - Error, - } -} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs index 61e88f7a37..5208edaa48 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs @@ -16,9 +16,9 @@ public sealed class SizeStatsCommand : CommandBase public override void Invoke() { - SizeStats(Generation.Gen0, isFree: false); - SizeStats(Generation.Gen1, isFree: false); - SizeStats(Generation.Gen2, isFree: false); + SizeStats(Generation.Generation0, isFree: false); + SizeStats(Generation.Generation1, isFree: false); + SizeStats(Generation.Generation2, isFree: false); SizeStats(Generation.Large, isFree: false); bool hasPinned = Runtime.Heap.Segments.Any(seg => seg.Kind == GCSegmentKind.Pinned); @@ -32,9 +32,9 @@ public override void Invoke() SizeStats(Generation.Frozen, isFree: false); } - SizeStats(Generation.Gen0, isFree: true); - SizeStats(Generation.Gen1, isFree: true); - SizeStats(Generation.Gen2, isFree: true); + SizeStats(Generation.Generation0, isFree: true); + SizeStats(Generation.Generation1, isFree: true); + SizeStats(Generation.Generation2, isFree: true); SizeStats(Generation.Large, isFree: true); if (hasPinned) @@ -62,7 +62,7 @@ private void SizeStats(Generation requestedGen, bool isFree) // If Kind == Ephemeral, we have to further filter by object generation if (seg.Kind == GCSegmentKind.Ephemeral) { - if (obj.GetGeneration(seg) != requestedGen) + if (seg.GetGeneration(obj) != requestedGen) { continue; } @@ -104,10 +104,10 @@ private static bool FilterByGeneration(ClrSegment seg, Generation gen) { return seg.Kind switch { - GCSegmentKind.Ephemeral => gen <= Generation.Gen2, - GCSegmentKind.Generation0 => gen == Generation.Gen0, - GCSegmentKind.Generation1 => gen == Generation.Gen1, - GCSegmentKind.Generation2 => gen == Generation.Gen2, + GCSegmentKind.Ephemeral => gen <= Generation.Generation2, + GCSegmentKind.Generation0 => gen == Generation.Generation0, + GCSegmentKind.Generation1 => gen == Generation.Generation1, + GCSegmentKind.Generation2 => gen == Generation.Generation2, GCSegmentKind.Frozen => gen == Generation.Frozen, GCSegmentKind.Pinned => gen == Generation.Pinned, GCSegmentKind.Large => gen == Generation.Large, From 1815f495c9086e04b40cf2cff2b1f58ff28bc3cf Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Tue, 4 Apr 2023 09:06:28 -0700 Subject: [PATCH 3/3] Add !dumpheap fragmentation statistics (#3799) In my previous !dumpheap change I overlooked the fragmentation output. This adds fragmentation output in the exact same was as the previous C++ code. The new code now validates the Free region is actually followed by the next object, and that those objects do not live on the Pinned, Frozen, or Large object heaps. --- .../DumpHeapCommand.cs | 7 ++- .../DumpHeapService.cs | 62 +++++++++++++++++-- .../NotReachableInRangeCommand.cs | 2 +- .../ObjSizeCommand.cs | 2 +- src/SOS/Strike/strike.cpp | 1 - 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs index 4ba19ae1cf..c62435f1d3 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs @@ -128,6 +128,7 @@ public override void Invoke() }); } + bool printFragmentation = false; DumpHeapService.DisplayKind displayKind = DumpHeapService.DisplayKind.Normal; if (ThinLock) { @@ -141,8 +142,12 @@ public override void Invoke() { displayKind = DumpHeapService.DisplayKind.Short; } + else + { + printFragmentation = true; + } - DumpHeap.PrintHeap(objectsToPrint, displayKind, StatOnly); + DumpHeap.PrintHeap(objectsToPrint, displayKind, StatOnly, printFragmentation); } private void ParseArguments() diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs index 8de3862967..f9687f8f33 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs @@ -18,6 +18,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands [ServiceExport(Scope = ServiceScope.Runtime)] public class DumpHeapService { + private const ulong FragmentationBlockMinSize = 512 * 1024; private const char StringReplacementCharacter = '.'; [ServiceImport] @@ -34,8 +35,12 @@ public enum DisplayKind Strings } - public void PrintHeap(IEnumerable objects, DisplayKind displayKind, bool statsOnly) + public void PrintHeap(IEnumerable objects, DisplayKind displayKind, bool statsOnly, bool printFragmentation) { + List<(ClrObject Free, ClrObject Next)> fragmentation = null; + Dictionary<(string String, ulong Size), uint> stringTable = null; + Dictionary stats = new(); + TableOutput thinLockOutput = null; TableOutput objectTable = new(Console, (12, "x12"), (12, "x12"), (12, ""), (0, "")); if (!statsOnly && (displayKind is DisplayKind.Normal or DisplayKind.Strings)) @@ -43,9 +48,7 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b objectTable.WriteRow("Address", "MT", "Size"); } - Dictionary stats = new(); - Dictionary<(string String, ulong Size), uint> stringTable = null; - + ClrObject lastFreeObject = default; foreach (ClrObject obj in objects) { if (displayKind == DisplayKind.ThinLock) @@ -77,6 +80,35 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b objectTable.WriteRow(new DmlDumpObj(obj), new DmlDumpHeap(obj.Type?.MethodTable ?? 0), size, obj.IsFree ? "Free" : ""); } + if (printFragmentation) + { + if (lastFreeObject.IsFree && obj.IsValid && !obj.IsFree) + { + // Check to see if the previous object lands directly before this one. We don't want + // to print fragmentation after changing segments, or after an allocation context. + if (lastFreeObject.Address + lastFreeObject.Size == obj.Address) + { + // Also, don't report fragmentation for Large/Pinned/Frozen segments. This check + // is a little slow, so we do this last. + ClrSegment seg = obj.Type.Heap.GetSegmentByAddress(obj); + if (seg is not null && seg.Kind is not GCSegmentKind.Large or GCSegmentKind.Pinned or GCSegmentKind.Frozen) + { + fragmentation ??= new(); + fragmentation.Add((lastFreeObject, obj)); + } + } + } + + if (obj.IsFree && size >= FragmentationBlockMinSize) + { + lastFreeObject = obj; + } + else + { + lastFreeObject = default; + } + } + if (displayKind == DisplayKind.Strings) { // We only read a maximum of 1024 characters for each string. This may lead to some collisions if strings are unique @@ -198,6 +230,28 @@ orderby Size Console.WriteLine($"Total {stats.Values.Sum(r => r.Count):n0} objects, {stats.Values.Sum(r => (long)r.Size):n0} bytes"); } } + + // Print fragmentation if we calculated it + PrintFragmentation(fragmentation); + } + + private void PrintFragmentation(List<(ClrObject Free, ClrObject Next)> fragmentation) + { + if (fragmentation is null || fragmentation.Count == 0) + { + return; + } + + TableOutput output = new(Console, (16, "x12"), (12, "n0"), (16, "x12")); + + Console.WriteLine(); + Console.WriteLine("Fragmented blocks larger than 0.5 MB:"); + output.WriteRow("Address", "Size", "Followed By"); + + foreach ((ClrObject free, ClrObject next) in fragmentation) + { + output.WriteRow(free.Address, free.Size, new DmlDumpObj(next.Address), next.Type?.Name ?? ""); + } } private string Sanitize(string str, int maxLen) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs index 55ed214c4a..59e399e303 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs @@ -62,7 +62,7 @@ public override void Invoke() ulong curr = start; IEnumerable liveObjs = EnumerateLiveObjectsInRange(end, curr); - DumpHeap.PrintHeap(liveObjs, Short ? DumpHeapService.DisplayKind.Short : DumpHeapService.DisplayKind.Normal, statsOnly: false); + DumpHeap.PrintHeap(liveObjs, Short ? DumpHeapService.DisplayKind.Short : DumpHeapService.DisplayKind.Normal, statsOnly: false, printFragmentation: false); } private IEnumerable EnumerateLiveObjectsInRange(ulong end, ulong curr) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs index 71b08ed536..0beb0e98f0 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs @@ -49,7 +49,7 @@ public override void Invoke() Console.WriteLine(); DumpHeapService.DisplayKind displayKind = Strings ? DumpHeapService.DisplayKind.Strings : DumpHeapService.DisplayKind.Normal; - DumpHeap.PrintHeap(GetTransitiveClosure(obj), displayKind, Stat); + DumpHeap.PrintHeap(GetTransitiveClosure(obj), displayKind, Stat, printFragmentation: false); } private static IEnumerable GetTransitiveClosure(ClrObject obj) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index f7715c32fa..e1470e45b0 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -3833,7 +3833,6 @@ DECLARE_API(DumpRuntimeTypes) return Status; } -#define MIN_FRAGMENTATIONBLOCK_BYTES (1024*512) namespace sos { class FragmentationBlock