LeakTypeInformation TryGetDefiniteLeaks(Heap heap, string name) { if (!heap.TryGetHeapshotTypeInfo(name, out var typeInfo)) { return(null); } var visitedRoots = new HashSet <HeapObject>(); int objectCount = 0; LeakGraph leakGraph = null; foreach (var obj in typeInfo.Objects) { visitedRoots.Clear(); bool objectIsLeaked = false; var paths = heap.Graph.GetPredecessors(obj, vertex => { if (heap.Roots.TryGetValue(vertex.Address, out var root)) { visitedRoots.Add(vertex); objectIsLeaked |= IsActualLeakSource(root.RootKind); } }); if (objectIsLeaked) { objectCount++; // TODO: Instead of just one graph, traverse all of them and group by common common paths. // Maybe create typePath graph for a given object type and reuse retention type information there if (leakGraph == null) { var objectRetentionGraph = new AdjacencyGraph <HeapObject, SReversedEdge <HeapObject, Edge <HeapObject> > >(); // TODO: We need to check if the root is finalizer or ephemeron, and not report the value. foreach (var root in visitedRoots) { if (paths.TryGetPath(root, out var edges)) { objectRetentionGraph.AddVerticesAndEdgeRange(edges); } } var graphviz = objectRetentionGraph.ToLeakGraphviz(heap); leakGraph = new LeakGraph(graphviz); } } } return(objectCount != 0 ? new LeakTypeInformation(name, objectCount, leakGraph) : null); }
public LeakTypeInformation(string className, int count, LeakGraph retentionGraph) { ClassName = className; Count = count; RetentionGraph = retentionGraph; }