private void VisitNode(MemoryNode currentNode) { MemoryNode oldMemNode = currentNode; // Get the generation for the current node. int generation = _HeapInfo.GenerationFor(oldMemNode.Address); // Create a MemoryNodeBuilder for the new graph that represents the current node // unless the current node is the root, as we've already created one. MemoryNodeBuilder newMemNodeBuilder = null; if (currentNode.Index == _OriginalMemoryGraph.RootIndex) { newMemNodeBuilder = _RootNode; } else { // Get the parent node. MemoryNodeBuilder parentMemNodeBuilder = null; if ((oldMemNode.Address != 0) && (generation > _GenerationToCondemn)) { if (generation == 1) { parentMemNodeBuilder = _Gen1RootNode; } else { parentMemNodeBuilder = _Gen2RootNode; } } else { parentMemNodeBuilder = _OldNodeToNewParentMap[(int)currentNode.Index]; } if (parentMemNodeBuilder == null) { parentMemNodeBuilder = _UnknownRootNode; } // Get the current node's type and object address. NodeType nodeType = _OriginalMemoryGraph.GetType(oldMemNode.TypeIndex, _OldNodeTypeStorage); // Create the new generation aware type name. string typeName = null; if (oldMemNode.Address != 0 && generation >= 0) { if (generation == 3) { typeName = string.Format("LOH: {0}", nodeType.Name); } else { typeName = string.Format("Gen{0}: {1}", generation, nodeType.Name); } } else { if (oldMemNode.Address != 0) { _Log.WriteLine(string.Format("Generation: {0}; Address: {1}; Type: {2}", generation, oldMemNode.Address, nodeType.Name)); } typeName = nodeType.Name; } // Create the new node. if (ShouldAddToGraph(oldMemNode, nodeType)) { if (oldMemNode.Address == 0) { newMemNodeBuilder = parentMemNodeBuilder.FindOrCreateChild(typeName); } else { NodeIndex newNodeIndex = _NewMemoryGraph.GetNodeIndex(oldMemNode.Address); newMemNodeBuilder = new MemoryNodeBuilder(_NewMemoryGraph, typeName, null, newNodeIndex); parentMemNodeBuilder.AddChild(newMemNodeBuilder); // Set the object size. if (generation <= _GenerationToCondemn) { newMemNodeBuilder.Size = oldMemNode.Size; } else { _Log.WriteLine("Ignoring Object Size: " + typeName); } } } } // Associate all children of the current node with this object's new MemoryNodeBuilder. for (NodeIndex childIndex = oldMemNode.GetFirstChildIndex(); childIndex != NodeIndex.Invalid; childIndex = oldMemNode.GetNextChildIndex()) { _OldNodeToNewParentMap[(int)childIndex] = newMemNodeBuilder; } }
internal void ProcessHeapSnapshot() { // Constants. const string PinnedHandlesNodeName = "[Pinned handle]"; const string AsyncPinnedHandlesNodeName = "[AsyncPinned handle]"; const string OverlappedDataTypeName = "System.Threading.OverlappedData"; const string ByteArrayTypeName = "System.Byte[]"; const string ObjectArrayTypeName = "System.Object[]"; // Open the heap dump. GCHeapDump dump = new GCHeapDump(_HeapSnapshotFilePath); _ProcessID = dump.ProcessID; // Get the heap info. DotNetHeapInfo heapInfo = dump.DotNetHeapInfo; // Get the memory graph. MemoryGraph memoryGraph = dump.MemoryGraph; // Get the root node. NodeIndex rootIndex = memoryGraph.RootIndex; Node rootNode = memoryGraph.GetNode(rootIndex, memoryGraph.AllocNodeStorage()); // Allocate additional nodes and node types. Node handleClassNodeStorage = memoryGraph.AllocNodeStorage(); NodeType handleClassNodeTypeStorage = memoryGraph.AllocTypeNodeStorage(); Node pinnedObjectNodeStorage = memoryGraph.AllocNodeStorage(); NodeType pinnedObjectNodeTypeStorage = memoryGraph.AllocTypeNodeStorage(); Node pinnedObjectChildNodeStorage = memoryGraph.AllocNodeStorage(); NodeType pinnedObjectChildNodeTypeStorage = memoryGraph.AllocTypeNodeStorage(); Node userObjectNodeStorage = memoryGraph.AllocNodeStorage(); NodeType userObjectNodeTypeStorage = memoryGraph.AllocTypeNodeStorage(); Node arrayBufferNodeStorage = memoryGraph.AllocNodeStorage(); NodeType arrayBufferNodeTypeStorage = memoryGraph.AllocTypeNodeStorage(); // Create a dictionary of pinned roots by pinned object address. Dictionary <Address, PinningRoot> pinnedRoots = new Dictionary <Address, PinningRoot>(); // Iterate over the nodes that represent handle type (e.g. [AsyncPinned Handle], [Pinned Handle], etc.) for (NodeIndex handleClassNodeIndex = rootNode.GetFirstChildIndex(); handleClassNodeIndex != NodeIndex.Invalid; handleClassNodeIndex = rootNode.GetNextChildIndex()) { // Get the node. Node handleClassNode = memoryGraph.GetNode(handleClassNodeIndex, handleClassNodeStorage); NodeType handleClassNodeType = handleClassNode.GetType(handleClassNodeTypeStorage); // Iterate over all pinned handles. if (PinnedHandlesNodeName.Equals(handleClassNodeType.Name)) { for (NodeIndex pinnedObjectNodeIndex = handleClassNode.GetFirstChildIndex(); pinnedObjectNodeIndex != NodeIndex.Invalid; pinnedObjectNodeIndex = handleClassNode.GetNextChildIndex()) { Node pinnedObjectNode = memoryGraph.GetNode(pinnedObjectNodeIndex, pinnedObjectNodeStorage); NodeType pinnedObjectNodeType = pinnedObjectNode.GetType(pinnedObjectNodeTypeStorage); // Create an object to represent the pinned objects. PinningRoot pinnedRoot = new PinningRoot(GCHandleKind.Pinned); List <Address> objectAddresses = new List <Address>(); // Get the address of the OverlappedData and add it to the list of pinned objects. Address pinnedObjectAddress = memoryGraph.GetAddress(pinnedObjectNodeIndex); UInt16 pinnedObjectGeneration = (UInt16)heapInfo.GenerationFor(pinnedObjectAddress); pinnedRoot.PinnedObjects = new PinnedObject[] { new PinnedObject(pinnedObjectAddress, pinnedObjectNodeType.Name, (uint)pinnedObjectNode.Size, pinnedObjectGeneration) }; pinnedRoots.Add(pinnedObjectAddress, pinnedRoot); } } // Iterate over asyncpinned handles. if (AsyncPinnedHandlesNodeName.Equals(handleClassNodeType.Name)) { for (NodeIndex pinnedObjectNodeIndex = handleClassNode.GetFirstChildIndex(); pinnedObjectNodeIndex != NodeIndex.Invalid; pinnedObjectNodeIndex = handleClassNode.GetNextChildIndex()) { Node pinnedObjectNode = memoryGraph.GetNode(pinnedObjectNodeIndex, pinnedObjectNodeStorage); NodeType pinnedObjectNodeType = pinnedObjectNode.GetType(pinnedObjectNodeTypeStorage); // Iterate over all OverlappedData objects. if (OverlappedDataTypeName.Equals(pinnedObjectNodeType.Name)) { // Create an object to represent the pinned objects. PinningRoot pinnedRoot = new PinningRoot(GCHandleKind.AsyncPinned); List <Address> objectAddresses = new List <Address>(); List <PinnedObject> pinnedObjects = new List <PinnedObject>(); // Get the address of the OverlappedData and add it to the list of pinned objects. Address pinnedObjectAddress = memoryGraph.GetAddress(pinnedObjectNodeIndex); UInt16 pinnedObjectGeneration = (UInt16)heapInfo.GenerationFor(pinnedObjectAddress); objectAddresses.Add(pinnedObjectAddress); pinnedObjects.Add(new PinnedObject(pinnedObjectAddress, pinnedObjectNodeType.Name, (uint)pinnedObjectNode.Size, pinnedObjectGeneration)); // Get the buffer or list of buffers that are pinned by the asyncpinned handle. for (NodeIndex userObjectNodeIndex = pinnedObjectNode.GetFirstChildIndex(); userObjectNodeIndex != NodeIndex.Invalid; userObjectNodeIndex = pinnedObjectNode.GetNextChildIndex()) { Node userObjectNode = memoryGraph.GetNode(userObjectNodeIndex, userObjectNodeStorage); NodeType userObjectNodeType = userObjectNode.GetType(userObjectNodeTypeStorage); if (userObjectNodeType.Name.StartsWith(ByteArrayTypeName)) { // Get the address. Address bufferAddress = memoryGraph.GetAddress(userObjectNodeIndex); UInt16 bufferGeneration = (UInt16)heapInfo.GenerationFor(bufferAddress); objectAddresses.Add(bufferAddress); pinnedObjects.Add(new PinnedObject(bufferAddress, userObjectNodeType.Name, (uint)userObjectNode.Size, bufferGeneration)); } else if (userObjectNodeType.Name.StartsWith(ObjectArrayTypeName)) { for (NodeIndex arrayBufferNodeIndex = userObjectNode.GetFirstChildIndex(); arrayBufferNodeIndex != NodeIndex.Invalid; arrayBufferNodeIndex = userObjectNode.GetNextChildIndex()) { Node arrayBufferNode = memoryGraph.GetNode(arrayBufferNodeIndex, arrayBufferNodeStorage); NodeType arrayBufferNodeType = arrayBufferNode.GetType(arrayBufferNodeTypeStorage); if (arrayBufferNodeType.Name.StartsWith(ByteArrayTypeName)) { // Get the address. Address bufferAddress = memoryGraph.GetAddress(arrayBufferNodeIndex); UInt16 bufferGeneration = (UInt16)heapInfo.GenerationFor(bufferAddress); objectAddresses.Add(bufferAddress); pinnedObjects.Add(new PinnedObject(bufferAddress, arrayBufferNodeType.Name, (uint)arrayBufferNode.Size, bufferGeneration)); } } } } // Assign the list of objects into the pinned root. pinnedRoot.PinnedObjects = pinnedObjects.ToArray(); foreach (Address objectAddress in objectAddresses) { // TODO: Handle objects that are pinned multiple times (?) pinnedRoots.Add(objectAddress, pinnedRoot); } } } } } _RootTable = pinnedRoots; }