protected IEnumerator <object> CaptureSnapshotTask(string targetFilename) { var now = DateTime.Now; var mem = new MemoryStatistics(Process); var psi = new ProcessStartInfo( Settings.UmdhPath, String.Format( "-g -p:{0} -f:\"{1}\"", Process.Id, targetFilename ) ); TemporaryFiles.Add(targetFilename); using (Activities.AddItem("Capturing heap snapshot")) yield return(Program.RunProcess(psi)); yield return(Future.RunInThread( () => File.AppendAllText(targetFilename, mem.GetFileText()) )); var fText = Future.RunInThread( () => File.ReadAllText(targetFilename) ); yield return(fText); var text = fText.Result; fText = null; yield return(FinishLoadingSnapshot(Snapshots.Count, now, targetFilename, text)); }
static void Serialize(ref SerializationContext context, ref MemoryStatistics input) { var cv = Mapper <MemoryStatistics> .GetColumnValues(input); var bw = new BinaryWriter(context.Stream, Encoding.UTF8); bw.Write(cv.Length); for (int i = 0; i < cv.Length; i++) { bw.Write((long)cv[i]); } bw.Flush(); }
public HeapSnapshotInfo( int index, DateTime timestamp, string filename, MemoryStatistics memory, HeapSnapshot snapshot ) : base( (from heap in snapshot.Heaps select(from alloc in heap.Allocations select(long) alloc.Size).Sum()).Sum(), (from heap in snapshot.Heaps select(from alloc in heap.Allocations select(long) alloc.Overhead).Sum()).Sum(), (from heap in snapshot.Heaps select(from alloc in heap.Allocations select(long)(alloc.Size + alloc.Overhead)).Sum()).Sum(), (from heap in snapshot.Heaps select heap.Allocations.Count).Sum() ) { Index = index; Timestamp = timestamp; Filename = filename; Memory = memory; _StrongRef = snapshot; HeapFragmentation = (from heap in snapshot.Heaps select heap.Info.EmptySpans).Sum() / (float)Math.Max(1, (from heap in snapshot.Heaps select heap.Allocations.Count).Sum()); LargestFreeHeapBlock = (from heap in snapshot.Heaps select heap.Info.LargestFreeSpan).Max(); LargestOccupiedHeapBlock = (from heap in snapshot.Heaps select heap.Info.LargestOccupiedSpan).Max(); AverageFreeBlockSize = (long)(from heap in snapshot.Heaps select(heap.Info.EstimatedFree) / Math.Max(heap.Info.EmptySpans, 1)).Average(); AverageOccupiedBlockSize = (long)(from heap in snapshot.Heaps select(heap.Info.TotalOverhead + heap.Info.TotalRequested) / Math.Max(heap.Info.OccupiedSpans, 1)).Average(); }
protected HeapSnapshotInfo( int index, DateTime timestamp, string filename, MemoryStatistics memory, float heapFragmentation, long largestFreeHeapBlock, long largestOccupiedHeapBlock, long averageFreeBlockSize, long averageOccupiedBlockSize, long bytesAllocated, long bytesOverhead, long bytesTotal, int allocationCount ) : base( bytesAllocated, bytesOverhead, bytesTotal, allocationCount ) { Index = index; Timestamp = timestamp; Filename = filename; Memory = memory; HeapFragmentation = heapFragmentation; LargestFreeHeapBlock = largestFreeHeapBlock; LargestOccupiedHeapBlock = largestOccupiedHeapBlock; AverageFreeBlockSize = averageFreeBlockSize; AverageOccupiedBlockSize = averageOccupiedBlockSize; _StrongRef = null; _WeakRef = null; }
public HeapSnapshot(int index, DateTime when, string filename, string text) { MemoryStatistics memory = new MemoryStatistics(); bool scanningForStart = true, scanningForMemory = false; Heap scanningHeap = null; var regexes = new Regexes(); int groupModule = regexes.SnapshotModule.GroupNumberFromName("module"); int groupModuleOffset = regexes.SnapshotModule.GroupNumberFromName("offset"); int groupModuleSize = regexes.SnapshotModule.GroupNumberFromName("size"); int groupHeaderId = regexes.HeapHeader.GroupNumberFromName("id"); int groupAllocOffset = regexes.Allocation.GroupNumberFromName("offset"); int groupAllocSize = regexes.Allocation.GroupNumberFromName("size"); int groupAllocOverhead = regexes.Allocation.GroupNumberFromName("overhead"); int groupAllocId = regexes.Allocation.GroupNumberFromName("id"); Match m; // Instead of allocating a tiny new UInt32[] for every traceback we read in, // we store groups of tracebacks into fixed-size buffers so that the GC has // less work to do when performing collections. Tracebacks are read-only after // being constructed, and all the tracebacks from a snapshot have the same // lifetime, so this works out well. var frameBuffer = new UInt32[FrameBufferSize]; int frameBufferCount = 0; var lr = new LineReader(text); LineReader.Line line; while (lr.ReadLine(out line)) { if (scanningHeap != null) { if (line.StartsWith("*-") && line.Contains("End of data for heap")) { scanningHeap.Allocations.TrimExcess(); scanningHeap = null; } else if (regexes.Allocation.TryMatch(ref line, out m)) { var tracebackId = UInt32.Parse(m.Groups[groupAllocId].Value, NumberStyles.HexNumber); Traceback traceback; if (!Tracebacks.TryGetValue(tracebackId, out traceback)) { // If the frame buffer could fill up while we're building our traceback, // let's allocate a new one. if (frameBufferCount >= frameBuffer.Length - MaxTracebackLength) { frameBuffer = new UInt32[frameBuffer.Length]; frameBufferCount = 0; } int firstFrame = frameBufferCount; // This is only valid if every allocation is followed by an empty line while (lr.ReadLine(out line)) { if (line.StartsWith("\t")) { frameBuffer[frameBufferCount++] = UInt32.Parse( line.ToString(), NumberStyles.HexNumber | NumberStyles.AllowLeadingWhite ); } else { lr.Rewind(ref line); break; } } Tracebacks.Add(traceback = new Traceback( tracebackId, new ArraySegment <UInt32>(frameBuffer, firstFrame, frameBufferCount - firstFrame) )); } scanningHeap.Allocations.Add(new Allocation( UInt32.Parse(m.Groups[groupAllocOffset].Value, NumberStyles.HexNumber), UInt32.Parse(m.Groups[groupAllocSize].Value, NumberStyles.HexNumber), UInt32.Parse(m.Groups[groupAllocOverhead].Value, NumberStyles.HexNumber), traceback.ID )); } } else if (scanningForMemory) { if (regexes.HeapHeader.TryMatch(ref line, out m)) { scanningHeap = new Heap(index, UInt32.Parse(m.Groups[groupHeaderId].Value, NumberStyles.HexNumber)); Heaps.Add(scanningHeap); } else if (line.StartsWith("// Memory=")) { memory = new MemoryStatistics(line.ToString()); scanningForMemory = false; break; } else { continue; } } else if (scanningForStart) { if (line.Contains("Loaded modules")) { scanningForStart = false; } else if (line.Contains("Start of data for heap")) { break; } else { continue; } } else { if (!regexes.SnapshotModule.TryMatch(ref line, out m)) { if (line.Contains("Process modules enumerated")) { scanningForMemory = true; } else { continue; } } else { var modulePath = Path.GetFullPath(m.Groups[groupModule].Value).ToLowerInvariant(); Modules.Add(new Module( modulePath, UInt32.Parse(m.Groups[groupModuleOffset].Value, System.Globalization.NumberStyles.HexNumber), UInt32.Parse(m.Groups[groupModuleSize].Value, System.Globalization.NumberStyles.HexNumber) )); } } } foreach (var heap in Heaps) { heap.Allocations.Sort( (lhs, rhs) => lhs.Address.CompareTo(rhs.Address) ); heap.ComputeStatistics(); } Info = new HeapSnapshotInfo(index, when, filename, memory, this); }
static void Deserialize(ref DeserializationContext context, out MemoryStatistics output) { var br = new BinaryReader(context.Stream, Encoding.UTF8); output = new MemoryStatistics(br); }