public void VariableRootTest() { // Test to make sure that a specific static and local variable exist. using DataTarget dt = TestTargets.Types.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; IEnumerable <IClrRoot> fooRoots = from root in heap.EnumerateRoots() where root.Object.Type.Name == "Foo" select root; IClrRoot[] localVarRoots = fooRoots.Where(r => r.RootKind == ClrRootKind.Stack).ToArray(); ClrThread thread = runtime.GetMainThread(); ClrStackFrame main = thread.GetFrame("Main"); ClrStackFrame inner = thread.GetFrame("Inner"); ulong low = thread.StackBase; ulong high = thread.StackLimit; // Account for different platform stack direction. if (low > high) { ulong tmp = low; low = high; high = tmp; } foreach (IClrRoot localVarRoot in localVarRoots) { Assert.True(low <= localVarRoot.Address && localVarRoot.Address <= high); } }
public bool Build(int chunkSize, string indexFileName, bool enumerateAllRoots) { if (chunkSize < 256 || chunkSize > 1048576 || chunkSize % 16 != 0) { _context.WriteErrorLine("Chunk size must be between 256 bytes and 1MB, and must be a multiple of 16."); return(false); } _chunkSize = chunkSize; _staticRootsEnumerated = enumerateAllRoots; Measure(() => { _allRoots = (from root in _heap.EnumerateRoots(enumerateStatics: enumerateAllRoots) select new SimplifiedRoot(root)).ToList(); }, "Enumerating roots"); // Build an index of N-byte chunks in all heap segments. The index is from chunk-id (int?) to // the first non-free object in the chunk (not to start of the chunk, which could be in the middle // of an object). If a chunk is completely empty or doesn't contain the start of any object, it // doesn't have an id. Measure(BuildChunks, "Building chunks"); // Traverse all object relationships on the heap from roots. For each chunk, specify which other // chunks contain references to objects in that chunk. When traversing this information, we need to // keep in mind that roots can also contain references to objects in the chunk -- we don't store this // information again because it's very easy to obtain by enumerating the roots. This decision can be // changed if root enumeration turns out to be slow when there are many roots. // Note that only live objects are being enumerated. For dead objects, it's not interesting to ask who // has a reference to the object -- because the referencing object is also dead. Measure(BuildChunkIndex, "Building chunk index"); DisplayStatistics(); if (!String.IsNullOrEmpty(indexFileName)) { Measure(() => Save(indexFileName), "Saving index to disk"); } else { _context.WriteWarningLine("You did not specify a file name, so the index will be stored only in memory. " + "If you plan to perform further analysis in another session, it is recommended that you store " + "the index to disk and later load it using the !lhi command."); } return(true); }
private void CalculateTypeStatisticsPhase2(ClrHeap heap, Regex typesToReportStatisticsOnRegex, HashSet <ulong> markedObjects, TypeStatistics typeStatistics) { typeStatistics.MemoryProfilingStopwatch.Start(); HashSet <ulong> visitedObjects = new HashSet <ulong>(); Queue <ClrObject> objectQueue = new Queue <ClrObject>(); // Start with exclusive = inclusive and walk the heap from roots looking for objects to subtract from this number. typeStatistics.ExclusiveRetainedBytes = typeStatistics.InclusiveRetainedBytes; foreach (ClrRoot root in heap.EnumerateRoots()) { // Interested only in roots outside of our marked inclusive graph. if (!markedObjects.Contains(root.Object)) { ClrObject rootObj = heap.GetObject(root.Object); objectQueue.Enqueue(rootObj); visitedObjects.Add(root.Object); while (objectQueue.Count > 0) { ClrObject obj = objectQueue.Dequeue(); if (obj.IsNull || obj.Type == null) { continue; } // We stop the walk when we see an object of a type we are reporting statistics on. if (!typesToReportStatisticsOnRegex.IsMatch(obj.Type.Name)) { if (markedObjects.Contains(obj.Address)) { // Not an object of a type we are reporting statistics on but it is part of the inclusive object graph. // This means that it must not be reported in the exclusive bytes. typeStatistics.ExclusiveRetainedBytes -= obj.Size; markedObjects.Remove(obj.Address); } // Follow all references. foreach (var reference in obj.EnumerateObjectReferences()) { if (!reference.IsNull && !visitedObjects.Contains(reference.Address)) { visitedObjects.Add(reference.Address); objectQueue.Enqueue(reference); } } } } } } typeStatistics.MemoryProfilingStopwatch.Stop(); }
private void FindAliveObjects([CanBeNull] ClrHeap heap) { if (heap == null) { return; } foreach (ClrRoot clrRoot in heap.EnumerateRoots()) { this.EnumerateRootReferences(clrRoot.Object, this.AliveObjectAdresses, this.AliveObjectsByType, heap); } }
public IEnumerable <IClrObject> ExploreFromRoots() { var reader = new ClrObjectReader(); foreach (var root in heap.EnumerateRoots()) { if (root.Object == 0) { continue; } if (!visited.Add(root.Object)) { continue; } if (root.Kind == GCRootKind.Finalizer) { continue; } if (root.Address == 0) { continue; } if (!reader.IsValidObjectType(root.Type)) { continue; } yield return(reader.ReadGCRoot(root)); CollectChildren(root.Type, root.Object); } while (pending.Count > 0) { var address = pending.Pop(); if (!visited.Add(address)) { continue; } var type = heap.GetObjectType(address); if (!reader.IsValidObjectType(type)) { continue; } yield return(reader.ReadFromAddress(type, address)); CollectChildren(type, address); } }
public void EnumerateMethodTableTest() { using (DataTarget dt = TestTargets.AppDomains.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; ulong[] fooObjects = (from obj in heap.EnumerateObjectAddresses() let t = heap.GetObjectType(obj) where t.Name == "Foo" select obj).ToArray(); // There are exactly two Foo objects in the process, one in each app domain. // They will have different method tables. Assert.Equal(2, fooObjects.Length); ClrType fooType = heap.GetObjectType(fooObjects[0]); Assert.NotSame(fooType, heap.GetObjectType(fooObjects[1])); ClrRoot appDomainsFoo = (from root in heap.EnumerateRoots(true) where root.Kind == GCRootKind.StaticVar && root.Type == fooType select root).Single(); ulong nestedExceptionFoo = fooObjects.Where(obj => obj != appDomainsFoo.Object).Single(); ClrType nestedExceptionFooType = heap.GetObjectType(nestedExceptionFoo); Assert.NotSame(nestedExceptionFooType, appDomainsFoo.Type); ulong nestedExceptionFooMethodTable = dt.DataReader.ReadPointerUnsafe(nestedExceptionFoo); ulong appDomainsFooMethodTable = dt.DataReader.ReadPointerUnsafe(appDomainsFoo.Object); // These are in different domains and should have different type handles: Assert.NotEqual(nestedExceptionFooMethodTable, appDomainsFooMethodTable); // The MethodTable returned by ClrType should always be the method table that lives in the "first" // AppDomain (in order of ClrAppDomain.Id). Assert.Equal(appDomainsFooMethodTable, fooType.MethodTable); // Ensure that we enumerate two type handles and that they match the method tables we have above. ulong[] methodTableEnumeration = fooType.EnumerateMethodTables().ToArray(); Assert.Equal(2, methodTableEnumeration.Length); // These also need to be enumerated in ClrAppDomain.Id order Assert.Equal(appDomainsFooMethodTable, methodTableEnumeration[0]); Assert.Equal(nestedExceptionFooMethodTable, methodTableEnumeration[1]); } }
public IEnumerable <DotNetObject> EnumerateObjects() { var roots = new List <DotNetObject>(); var visited = new HashSet <ulong>(); foreach (var root in heap.EnumerateRoots()) { heap.EnumerateObjectAddresses(); if (root?.Type == null || root.Name == null) { continue; } var name = root.Name; string prefix; if ((prefix = ClrGlobals.ExcludePrefix.FirstOrDefault(p => name.StartsWith(p, StringComparison.InvariantCultureIgnoreCase))) != null) { name = name.Substring(prefix.Length); } if (ClrGlobals.ExcludeRootNamespaces.Any(n => name.StartsWith(n, StringComparison.InvariantCultureIgnoreCase))) { continue; } if (ClrGlobals.ExcludeNames.Any(n => name.StartsWith(n, StringComparison.InvariantCultureIgnoreCase))) { continue; } var dot = name.LastIndexOf('.'); if (dot != -1) { name = name.Substring(dot + 1); } if (!visited.Add(root.Object)) { continue; } var obj = new DotNetObject(root.Object, root.Type, name); roots.Add(obj); RecursiveEnumerateObjects(visited, obj, obj.Reference, obj.Type); } return(roots); }
public static ulong[] GetRootAddresses(ClrHeap heap) { var roots = heap.EnumerateRoots(true); var dct = new Dictionary <ulong, ulong>(); foreach (var root in roots) { ulong rootAddr = root.Address; ulong objAddr = root.Object; if (rootAddr != 0Ul) { rootAddr = Utils.SetRooted(root.Address); ulong addr; if (dct.TryGetValue(root.Address, out addr)) { dct[root.Address] = rootAddr | addr; } else { dct.Add(root.Address, rootAddr); } } if (objAddr != 0UL) { if (root.Kind == GCRootKind.Finalizer) { objAddr = Utils.SetAsFinalizer(root.Object); } objAddr = Utils.SetRooted(objAddr); ulong addr; if (dct.TryGetValue(root.Object, out addr)) { dct[root.Object] = addr | objAddr; } else { dct.Add(root.Object, objAddr); } } } var addrAry = dct.Values.ToArray(); var cmp = new Utils.AddressCmpAcs(); Array.Sort(addrAry, cmp); return(addrAry); }
private static List <ClrRoot> FillRootDictionary(ClrHeap heap) { List <ClrRoot> roots = new List <ClrRoot>(heap.EnumerateRoots()); foreach (var root in roots) { List <ClrRoot> list; if (!m_rootDict.TryGetValue(root.Object, out list)) { list = new List <ClrRoot>(); m_rootDict[root.Object] = list; } list.Add(root); } return(roots); }
public void VariableRootTest() { // Test to make sure that a specific static and local variable exist. using (DataTarget dt = TestTargets.Types.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; heap.StackwalkPolicy = ClrRootStackwalkPolicy.Exact; var fooRoots = from root in heap.EnumerateRoots() where root.Type.Name == "Foo" select root; ClrRoot staticRoot = fooRoots.Where(r => r.Kind == GCRootKind.StaticVar).Single(); Assert.IsTrue(staticRoot.Name.Contains("s_foo")); var arr = fooRoots.Where(r => r.Kind == GCRootKind.LocalVar).ToArray(); ClrRoot localVarRoot = fooRoots.Where(r => r.Kind == GCRootKind.LocalVar).Single(); ClrThread thread = runtime.GetMainThread(); ClrStackFrame main = thread.GetFrame("Main"); ClrStackFrame inner = thread.GetFrame("Inner"); ulong low = thread.StackBase; ulong high = thread.StackLimit; // Account for different platform stack direction. if (low > high) { ulong tmp = low; low = high; high = tmp; } Assert.IsTrue(low <= localVarRoot.Address && localVarRoot.Address <= high); } }
public void Execute(ClrHeap heap) { //var rootNames = new HashSet<string>(); //rootNames.Add("Strong handle"); //rootNames.Add("Pinned handle"); //rootNames.Add("SizedRef handle"); //rootNames.Add("AsyncPinned handle"); //rootNames.Add("RefCount handle"); //rootNames.Add("finalization handle"); //rootNames.Add("local var"); //foreach (var rootName in rootNames) //{ var dict = new Dictionary <string, ulong>(); foreach (var root in heap.EnumerateRoots()) { //if (root.Name == rootName) //{ if (dict.ContainsKey(root.Name)) { dict[root.Name]++; } else { dict[root.Name] = 1; } //} } //File.WriteAllLines($"{rootName}.txt", dict.Select(pair => pair.ToString())); //} foreach (var keyValuePair in dict.OrderBy(x => x.Value)) { Console.WriteLine(keyValuePair); } }
/// <summary> /// Enumerates all objects reachable from GC roots in the given heap. Each object is returned exactly once. /// </summary> private IEnumerable <ClrObject> EnumerateRootedObjects(ClrHeap heap) { HashSet <ulong> visitedObjects = new HashSet <ulong>(); Queue <ClrObject> objectQueue = new Queue <ClrObject>(); foreach (ClrRoot root in heap.EnumerateRoots()) { if (!visitedObjects.Contains(root.Object)) { ClrObject rootObj = heap.GetObject(root.Object); objectQueue.Enqueue(rootObj); visitedObjects.Add(root.Object); if (rootObj.Type != null) { yield return(rootObj); } while (objectQueue.Count > 0) { ClrObject obj = objectQueue.Dequeue(); if (obj.IsNull || obj.Type == null) { continue; } // Follow all references. foreach (var reference in obj.EnumerateObjectReferences()) { if (!reference.IsNull && !visitedObjects.Contains(reference.Address)) { objectQueue.Enqueue(reference); visitedObjects.Add(reference.Address); yield return(reference); } } } } } }
/// <summary> /// See http://stackoverflow.com/questions/35268695/what-is-the-clrmd-equivalent-to-dumpheap-live /// </summary> /// <param name="heap"></param> /// <returns></returns> private static ObjectSet GetLiveObjects(ClrHeap heap) { ObjectSet considered = new ObjectSet(heap); Stack <ulong> eval = new Stack <ulong>(); foreach (var root in heap.EnumerateRoots()) { eval.Push(root.Object); } while (eval.Count > 0) { ulong obj = eval.Pop(); if (considered.Contains(obj)) { continue; } considered.Add(obj); var type = heap.GetObjectType(obj); if (type == null) // Only if heap corruption { continue; } type.EnumerateRefsOfObjectCarefully(obj, delegate(ulong child, int offset) { if (child != 0 && !considered.Contains(child)) { eval.Push(child); } }); } return(considered); }
/// <summary> /// Enumerate the roots of the process. (That is, all objects which keep other objects alive.) /// Equivalent to EnumerateRoots(true). /// </summary> /// <returns>IEnumerable<IClrRoot>.</returns> /// <inheritdoc /> public IEnumerable <IClrRoot> EnumerateRoots() => Heap.EnumerateRoots().Select(Converter.Convert);
private static void DumpRetention(DataTarget dataTarget, ClrInfo clrVersion, ClrRuntime runtime, ClrAppDomain appDomain, ClrHeap heap, string targetType) { var graph = new Graph(); Console.WriteLine("## What's the retention path of the {0} object?", targetType); Console.WriteLine(""); foreach (var ptr in heap.EnumerateObjectAddresses()) { var type = heap.GetObjectType(ptr); if (type == null || type.Name != targetType) { continue; } // Enumerate roots and try to find the current object var stack = new Stack <ulong>(); foreach (var root in heap.EnumerateRoots()) { stack.Clear(); stack.Push(root.Object); if (GetPathToObject(heap, ptr, stack, new HashSet <ulong>())) { // Print retention path var depth = 0; var previousAddress = (ulong)0; foreach (var address in stack) { var t = heap.GetObjectType(address); if (t == null) { continue; } Console.WriteLine("{0} {1} - {2} - {3} bytes", new string('+', depth++), address, t.Name, t.GetSize(address)); graph.AddNode(address.ToString()).LabelText = $"{t.Name} ({address})"; if (previousAddress > 0 && !graph.Edges.Any(e => e.Source == previousAddress.ToString() && e.Target == address.ToString())) { graph.AddEdge(previousAddress.ToString(), address.ToString()); } previousAddress = address; } Console.WriteLine(); } } } Console.ReadLine(); // Render graph var width = 1600; var renderer = new GraphRenderer(graph); renderer.CalculateLayout(); var bitmap = new Bitmap(width, (int)(graph.Height * (width / graph.Width)), PixelFormat.Format32bppRgb); renderer.Render(bitmap); bitmap.Save("test.png"); Process.Start("test.png"); }
public HeapIndex(ClrHeap heap) { // Evaluation stack Stack <ulong> eval = new Stack <ulong>(); _roots = new ObjectSet(heap); _walkableFromRoot = new ObjectSet(heap); foreach (var clrRoot in heap.EnumerateRoots()) { _roots.Add(clrRoot.Object); eval.Push(clrRoot.Object); } while (eval.Count > 0) { // Pop an object, ignore it if we've seen it before. var address = eval.Pop(); if (_walkableFromRoot.Contains(address)) { continue; } _walkableFromRoot.Add(address); // Grab the type. We will only get null here in the case of heap corruption. ClrType?type = heap.GetObjectType(address); if (type == null) { continue; } // Now enumerate all objects that this object points to, add them to the // evaluation stack if we haven't seen them before. if (type.IsArray) { EnumerateArrayElements(address); } else { EnumerateFields(type, address); } } void EnumerateArrayElements(ulong address) { var obj = heap.GetObject(address); var array = obj.AsArray(); var componentType = ((ClrmdArrayType)array.Type).ComponentType; if (componentType.IsObjectReference) { foreach (var arrayElement in ArrayProxy.EnumerateObjectItems(array)) { if (!arrayElement.IsNull) { AddReference(address, arrayElement.Address); eval.Push(arrayElement.Address); } } } else { // throw new NotSupportedException($"Enumerating array of {componentType} type is not supported"); } } void EnumerateFields(ClrType?type, ulong address) { foreach (var instanceField in type.Fields) { if (instanceField.IsObjectReference) { var fieldObject = instanceField.ReadObject(address, false); if (!fieldObject.IsNull) { AddReference(address, fieldObject.Address); eval.Push(fieldObject.Address); } } } } }
public void EnumerateRoots(out IMDRootEnum ppEnum) { ppEnum = new MDRootEnum(new List <ClrRoot>(m_heap.EnumerateRoots())); }
public static ReferenceGraph Build(ClrHeap heap, HashSet <ulong> targetAddresses, CancellationToken token = default) { var graph = new ReferenceGraph(); var seen = new ObjectSet(heap); var stack = new HeapWalkStack(); var nodeByAddress = new Dictionary <ulong, ReferenceGraphNode>(); var chainCache = new Dictionary <(uint metadataToken, int fieldOffset), List <FieldReference> >(); // For each root foreach (var root in heap.EnumerateRoots(enumerateStatics: true)) { stack.Clear(); if (root.Type == null) { // This happens, though not sure why continue; } stack.Push(new ClrObjectReference(-1, root.Object, root.Type)); while (!stack.IsEmpty) { token.ThrowIfCancellationRequested(); ref var top = ref stack.Peek(); if (top.Enumerator.MoveNext()) { var o = top.Enumerator.Current; if (targetAddresses.Contains(o.Address)) { // Found a match stack.Push(o); // Ensure our stack's root is registered with the graph ref var rootLevel = ref stack[0]; if (rootLevel.GraphNode == null) { var rootNode = new RootGraphNode(root); nodeByAddress[root.Object] = rootNode; rootLevel.GraphNode = rootNode; graph.Roots.Add(rootNode); } // Build path through graph for the current stack // Skip the first node as it's always non-null for (var i = 1; i < stack.Count; i++) { ref var level = ref stack[i]; // Ensure all levels have a graph node object if (level.GraphNode == null) { if (!nodeByAddress.TryGetValue(level.Reference.Address, out var node)) { node = new ReferenceGraphNode(level.Reference.Object); nodeByAddress[level.Reference.Address] = node; if (i == stack.Count - 1) { graph.TargetSet.Add(node); } } level.GraphNode = node; ref var levelBefore = ref stack[i - 1]; var referenceChain = GetChain(levelBefore.GraphNode.Object.Type, level.Reference); level.GraphNode.Referrers.Add((node: levelBefore.GraphNode, referenceChain, fieldOffset: level.Reference.FieldOffset)); // levelBefore.GraphNode.References.Add((node: level.GraphNode, referenceChain)); } } stack.Pop(); }
public static ValueTuple <ulong[], int, int> GetFlaggedRoots(ClrHeap heap, string[] typeNames, StringIdDct strIds, string rootPath, out string error) { error = null; try { Dictionary <ulong, ulong> dct = new Dictionary <ulong, ulong>(1024 * 512); List <ClrtRoot>[] ourRoots = new List <ClrtRoot> [(int)GCRootKind.Max + 1]; for (int i = 0, icnt = (int)GCRootKind.Max + 1; i < icnt; ++i) { ourRoots[i] = new List <ClrtRoot>(256); } var roots = heap.EnumerateRoots(true); //ulong savedAddr; int finalizerCount = 0; int rootCount = 0; foreach (var root in roots) { ulong rootAddr = root.Address; ulong objAddr = root.Object; ulong flaggedRootAddr = rootAddr; ulong flaggedObjAddr = objAddr; int typeId; string typeName; if (root.Type == null) { var clrType = heap.GetObjectType(objAddr); typeName = clrType == null ? Constants.UnknownName : clrType.Name; } else { typeName = root.Type.Name; } typeId = Array.BinarySearch(typeNames, typeName, StringComparer.Ordinal); if (typeId < 0) { typeId = Constants.InvalidIndex; } string rootName = root.Name == null ? Constants.UnknownName : root.Name; var nameId = strIds.JustGetId(rootName); var clrtRoot = new ClrtRoot(root, typeId, nameId); ourRoots[(int)root.Kind].Add(clrtRoot); switch (root.Kind) { case GCRootKind.Finalizer: ++finalizerCount; if (objAddr != 0UL) { flaggedObjAddr = Utils.SetAsFinalizer(flaggedObjAddr); } if (rootAddr != 0UL) { flaggedRootAddr = Utils.SetAsFinalizer(flaggedRootAddr); } break; case GCRootKind.LocalVar: if (objAddr != 0UL) { flaggedObjAddr = Utils.SetAsLocal(flaggedObjAddr); } if (rootAddr != 0UL) { flaggedRootAddr = Utils.SetAsLocal(flaggedRootAddr); } break; default: ++rootCount; flaggedObjAddr = Utils.SetAsRoot(flaggedObjAddr); if (objAddr != 0UL) { flaggedObjAddr = Utils.SetAsRoot(flaggedObjAddr); } if (rootAddr != 0UL) { flaggedRootAddr = Utils.SetAsRoot(flaggedRootAddr); } break; } SetFlaggedAddress(dct, objAddr, flaggedObjAddr); SetFlaggedAddress(dct, rootAddr, flaggedRootAddr); } var rootCmp = new ClrtRootObjCmp(); for (int i = 0, icnt = (int)GCRootKind.Max + 1; i < icnt; ++i) { ourRoots[i].Sort(rootCmp); } Save(rootPath, ourRoots, out error); ulong[] rootAddrs = dct.Values.ToArray(); Utils.SortAddresses(rootAddrs); return(rootAddrs, rootCount, finalizerCount); } catch (Exception ex) { error = Utils.GetExceptionErrorString(ex); return(null, 0, 0); } }
// TODO JRD -- delete later public static ClrtRoots GetRoots(ClrHeap heap, ulong[] instances, int[] types, StringIdAsyncDct idDct) { var rootDct = new SortedDictionary <ulong, List <ClrtRoot> >(); var finalizeQue = new List <ulong>(1024 * 1024); var finalizeQueInstIds = new List <int>(1024 * 1024); List <ClrRoot> lstNotFoundObject = new List <ClrRoot>(); List <ClrtRoot> lstRoots = new List <ClrtRoot>(1024 * 64); foreach (var root in heap.EnumerateRoots()) { var rootObj = root.Object; if (root.Kind == GCRootKind.Finalizer) { finalizeQue.Add(rootObj); var obj = Array.BinarySearch(instances, rootObj); if (obj < 0) { obj = Constants.InvalidIndex; } finalizeQueInstIds.Add(obj); continue; } var rootAddr = root.Address; List <ClrtRoot> lst; if (rootDct.TryGetValue(rootAddr, out lst)) { int i = 0; int icnt = lst.Count; var rkind = root.Kind; for (; i < icnt; ++i) { if (rootObj == lst[i].Object && rkind == ClrtRoot.GetGCRootKind(lst[i].RootKind)) { break; } } if (i == icnt) { var rname = root.Name ?? Constants.NullName; var rnameId = idDct.JustGetId(rname); var obj = Array.BinarySearch(instances, rootObj); if (obj < 0) { lstNotFoundObject.Add(root); } var typeId = obj < 0 ? Constants.InvalidIndex : types[obj]; var clrtRoot = new ClrtRoot(root, typeId, rnameId, Constants.InvalidIndex, Constants.InvalidThreadId, Constants.InvalidIndex); lst.Add(clrtRoot); lstRoots.Add(clrtRoot); } } else { var rname = root.Name ?? Constants.NullName; var rnameId = idDct.JustGetId(rname); var obj = Array.BinarySearch(instances, rootObj); if (obj < 0) { lstNotFoundObject.Add(root); } var typeId = obj < 0 ? Constants.InvalidIndex : types[obj]; var clrtRoot = new ClrtRoot(root, typeId, rnameId, Constants.InvalidIndex, Constants.InvalidThreadId, Constants.InvalidIndex); rootDct.Add(rootAddr, new List <ClrtRoot>() { clrtRoot }); lstRoots.Add(clrtRoot); } } var rootAry = lstRoots.ToArray(); lstRoots.Clear(); lstRoots = null; ulong[] sortedObjs; int[] kindOffsets; int[] objMap; ulong[] sortedAddrs; int[] addrMap; SortRoots(rootAry, out kindOffsets, out sortedAddrs, out addrMap, out sortedObjs, out objMap); var finQueAry = finalizeQue.ToArray(); var finQueInstIdsAry = finalizeQueInstIds.ToArray(); Array.Sort(finQueAry, finQueInstIdsAry); return(new ClrtRoots(rootAry, kindOffsets, sortedAddrs, addrMap, sortedObjs, objMap, finQueAry, finQueInstIdsAry)); }
public static ValueTuple <ulong[], ulong[]> SetupRootAddresses(int rtm, ClrHeap heap, string[] typeNames, StringIdDct strIds, DumpFileMoniker fileMoniker, out string error) { error = null; try { var roots = heap.EnumerateRoots(true); var objSet = new HashSet <ulong>(new Utils.AddressEqualityComparer()); var finlSet = new HashSet <ulong>(new Utils.AddressEqualityComparer()); List <ClrtRoot>[] ourRoots = new List <ClrtRoot> [(int)GCRootKind.Max + 1]; for (int i = 0, icnt = (int)GCRootKind.Max + 1; i < icnt; ++i) { ourRoots[i] = new List <ClrtRoot>(256); } foreach (var root in roots) { ulong rootAddr = root.Address; ulong objAddr = root.Object; int typeId; string typeName; if (root.Type == null) { var clrType = heap.GetObjectType(objAddr); typeName = clrType == null ? Constants.UnknownName : clrType.Name; } else { typeName = root.Type.Name; } typeId = Array.BinarySearch(typeNames, typeName, StringComparer.Ordinal); if (typeId < 0) { typeId = Constants.InvalidIndex; } string rootName = root.Name == null ? Constants.UnknownName : root.Name; var nameId = strIds.JustGetId(rootName); var clrtRoot = new ClrtRoot(root, typeId, nameId); ourRoots[(int)root.Kind].Add(clrtRoot); if (objAddr != 0UL) { if (root.Kind == GCRootKind.Finalizer) { objAddr = Utils.SetAsFinalizer(objAddr); finlSet.Add(objAddr); } else { objAddr = Utils.SetRooted(objAddr); objSet.Add(objAddr); } } if (rootAddr != 0UL) { if (root.Kind == GCRootKind.Finalizer) { rootAddr = Utils.SetAsFinalizer(rootAddr); finlSet.Add(rootAddr); } else { rootAddr = Utils.SetRooted(rootAddr); objSet.Add(rootAddr); } } } // root infos TODO JRD -- Fix this // var rootCmp = new ClrtRootObjCmp(); for (int i = 0, icnt = (int)GCRootKind.Max + 1; i < icnt; ++i) { ourRoots[i].Sort(rootCmp); } // unique addresses // var addrAry = objSet.ToArray(); Array.Sort(addrAry, new Utils.AddressComparison()); var finlAry = finlSet.ToArray(); Array.Sort(finlAry, new Utils.AddressComparison()); if (!ClrtRootInfo.Save(rtm, ourRoots, fileMoniker, out error)) { return(new ValueTuple <ulong[], ulong[]>(null, null)); } return(new ValueTuple <ulong[], ulong[]>(addrAry, finlAry)); } catch (Exception ex) { error = Utils.GetExceptionErrorString(ex); return(new ValueTuple <ulong[], ulong[]>(null, null)); } }