/// <summary> /// Add a sample representing the pinned object allocation. /// </summary> private void WriteAllocationStack( Address objectAddress, PinningRoot pinnedRoot, PinningStackAnalysisObject liveObjectInfo) { // Get the pinned object from the pinned root. PinnedObject pinnedObject = null; foreach (PinnedObject o in pinnedRoot.PinnedObjects) { if (o.ObjectAddress == objectAddress) { pinnedObject = o; break; } } // This should not happen, but we put this here to ensure that we don't crash. if (null == pinnedObject) { System.Diagnostics.Debug.Assert(false, "Pinned object could not be found, but was found in the _RootTable."); return; } // Get the allocation call stack. StackSourceCallStackIndex rootCallStackIndex = liveObjectInfo.AllocStack; // Add the generation pseudo-node. string generationString = "GENERATION " + pinnedObject.Generation; StackSourceFrameIndex generationFrameIndex = _StackSource.Interner.FrameIntern(generationString); StackSourceCallStackIndex callStackIndex = _StackSource.Interner.CallStackIntern(generationFrameIndex, rootCallStackIndex); // Add the type of the object. string objectTypeString = "OBJECT_TYPE " + pinnedObject.ObjectType; StackSourceFrameIndex objectTypeFrameIndex = _StackSource.Interner.FrameIntern(objectTypeString); callStackIndex = _StackSource.Interner.CallStackIntern(objectTypeFrameIndex, callStackIndex); // Set the object instance. string objectInstanceString = "OBJECT_INSTANCE " + pinnedObject.ObjectAddress; StackSourceFrameIndex objectInstanceFrameIndex = _StackSource.Interner.FrameIntern(objectInstanceString); callStackIndex = _StackSource.Interner.CallStackIntern(objectInstanceFrameIndex, callStackIndex); // Setup the sample. _Sample.TimeRelativeMSec = liveObjectInfo.AllocationTimeRelativeMSec; _Sample.Metric = pinnedObject.ObjectSize; _Sample.StackIndex = callStackIndex; _StackSource.AddSample(_Sample); }
/// <summary> /// Write out a sample for each pin operation of the input object. /// </summary> private void WritePinningStacks( Address objectAddress, PinningRoot pinnedRoot, PinningStackAnalysisObject liveObjectInfo) { if (liveObjectInfo.PinInfo != null) { foreach (PinningStackAnalysisPinInfo pinInfo in liveObjectInfo.PinInfo) { // Get the pinning stack and the time. foreach (PinnedObject pinnedObject in pinnedRoot.PinnedObjects) { // Add the generation pseudo-node. string generationString = "GENERATION " + pinnedObject.Generation; StackSourceFrameIndex generationFrameIndex = _StackSource.Interner.FrameIntern(generationString); StackSourceCallStackIndex callStackIndex = _StackSource.Interner.CallStackIntern(generationFrameIndex, pinInfo.PinStack); // Add the root type. string rootTypeString = "ROOT_TYPE " + pinnedRoot.RootType.ToString(); StackSourceFrameIndex rootTypeFrameIndex = _StackSource.Interner.FrameIntern(rootTypeString); callStackIndex = _StackSource.Interner.CallStackIntern(rootTypeFrameIndex, callStackIndex); // Add the type of the object. string objectTypeString = "OBJECT_TYPE " + pinnedObject.ObjectType; StackSourceFrameIndex objectTypeFrameIndex = _StackSource.Interner.FrameIntern(objectTypeString); callStackIndex = _StackSource.Interner.CallStackIntern(objectTypeFrameIndex, callStackIndex); // Set the object instance. string objectInstanceString = "OBJECT_INSTANCE " + pinnedObject.ObjectAddress; StackSourceFrameIndex objectInstanceFrameIndex = _StackSource.Interner.FrameIntern(objectInstanceString); callStackIndex = _StackSource.Interner.CallStackIntern(objectInstanceFrameIndex, callStackIndex); // Set the metric to 1 since the metric represents the number of pin operations. _Sample.Metric = 1; // Set the call stack. _Sample.TimeRelativeMSec = pinInfo.PinTimeRelativeMSec; _Sample.StackIndex = callStackIndex; _StackSource.AddSample(_Sample); } } } }
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; }