private MemoryAnalyzer(DataTarget dataTarget) { // TODO: Exit gracefully for memory dumps from different platforms m_dataTarget = dataTarget; string dacLocation = m_dataTarget.ClrVersions[0].TryGetDacLocation(); if (String.IsNullOrEmpty(dacLocation)) throw new ArgumentException("Cannot find DAC location for process"); m_runtime = m_dataTarget.CreateRuntime(dacLocation); m_heap = m_runtime.GetHeap(); }
public void Execute(CommandExecutionContext context) { _context = context; if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress)) return; _heap = context.Heap; if (!_heap.CanWalkHeap) { context.WriteErrorLine("The heap is not in a walkable state."); return; } var type = _heap.GetObjectType(ObjectAddress); _visitedObjects = new ObjectSet(_heap); _targets[ObjectAddress] = new Node(ObjectAddress, type); FillRootDictionary(); foreach (var root in _roots) { if (_visitedRoots.Contains(root) || _visitedObjects.Contains(root.Object)) continue; Node path = TryFindPathToTarget(root); if (path != null) PrintOnePath(path); } }
public ObjectSet(ClrHeap heap) { _shift = IntPtr.Size == 4 ? 3 : 4; int count = heap.Segments.Count; _data = new BitArray[count]; _entries = new Entry[count]; #if DEBUG ulong last = 0; #endif for (int i = 0; i < count; ++i) { var seg = heap.Segments[i]; #if DEBUG Debug.Assert(last < seg.Start); last = seg.Start; #endif _data[i] = new BitArray(GetBitOffset(seg.Length)); _entries[i].Low = seg.Start; _entries[i].High = seg.End; _entries[i].Index = i; } }
// Returns all objects being kept alive by the input object // Based off the code at https://github.com/Microsoft/clrmd/blob/master/Documentation/WalkingTheHeap.md public static List<ulong> GetReferencedObjects(ClrHeap heap, ulong obj) { List<ulong> references = new List<ulong>(); Stack<ulong> eval = new Stack<ulong>(); HashSet<ulong> considered = new HashSet<ulong>(); eval.Push(obj); while (eval.Count > 0) { obj = eval.Pop(); if (considered.Contains(obj)) continue; considered.Add(obj); // Grab the type. We will only get null here in the case of heap corruption. ClrType type = heap.GetObjectType(obj); if (type == null) continue; references.Add(obj); // Now enumerate all objects that this object points to, add them to the // evaluation stack if we haven't seen them before. type.EnumerateRefsOfObjectCarefully(obj, delegate (ulong child, int offset) { if (child != 0 && !considered.Contains(child)) eval.Push(child); }); } return references; }
private static IEnumerable<Tuple<ulong, ClrType>> EnumerateFromObjectSet(ClrHeap heap, IEnumerable<ulong> objects) { var toGoThrough = new Stack<ulong>(objects); var seen = new ObjectSet(heap); while (toGoThrough.Count > 0) { var obj = toGoThrough.Pop(); if (seen.Contains(obj)) continue; seen.Add(obj); var type = heap.GetObjectType(obj); if (type == null || type.IsFree || String.IsNullOrEmpty(type.Name)) continue; yield return new Tuple<ulong, ClrType>(obj, type); type.EnumerateRefsOfObject(obj, (child, _) => { if (child != 0 && !seen.Contains(child)) { toGoThrough.Push(child); } }); } }
public ClrNullValue(ClrHeap heap) { foreach (var type in heap.EnumerateTypes()) { s_free = type; break; } }
/// <summary> /// Converts the specified heap. /// </summary> /// <param name="heap">The heap.</param> /// <returns>IClrHeap.</returns> public IClrHeap Convert(ClrMd.ClrHeap heap) { if (heap == null) { return(null); } var item = new HeapAdapter(this, heap); return(Cache.GetOrAdd <IClrHeap>(heap, () => item, () => item.Setup())); }
public ClrDynamicClass(ClrHeap heap, ClrType type) { if (heap == null) throw new ArgumentNullException("heap"); if (type == null) throw new ArgumentNullException("type"); m_heap = heap; m_type = type; }
public ClrObject(ClrHeap heap, ClrType type, ulong addr, bool inner) { if (heap == null) throw new ArgumentNullException("heap"); m_addr = addr; m_inner = inner; m_heap = heap; // For interior pointers (structs inside other objects), we simply have to trust the caller // gave us the right thing. m_type = inner ? type : heap.GetObjectType(addr); }
public ClrHeapDecorator(ClrRuntime clrRuntime, ThreadDispatcher threadDispatcher) { _threadDispatcher = threadDispatcher; _clrHeap = threadDispatcher.Process(() => clrRuntime.GetHeap()); _threadDispatcher.Process(()=> { objectIndex = IndexBuilder.Build(_clrHeap); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; }); }
public static MultiElementDictionary2<ulong> Build(ClrHeap heap) { var result = new MultiElementDictionary2<ulong>(); foreach (var objRef in heap.EnumerateObjects()) { var type = heap.GetObjectType(objRef); result.Add(type.Name, objRef); } return result; }
static object Format(ClrHeap heap, object val) { if (val == null) return "{null}"; if (val is ulong) { ulong addr = (ulong)val; var type = heap.GetObjectType(addr); if (type != null && type.Name == "System.String") return type.GetValue(addr); else return ((ulong)val).ToString("X"); } return val; }
public ClrObject(ClrHeap heap, ClrType type, ulong addr) { if (heap == null) throw new ArgumentNullException("heap"); m_addr = addr; m_heap = heap; if (addr != 0) { var gcType = heap.GetObjectType(addr); if (gcType != null) type = gcType; } m_type = type; }
internal virtual IEnumerable <ClrRoot> EnumerateStackReferences(ClrThread thread, bool includeDead) { Address stackBase = thread.StackBase; Address stackLimit = thread.StackLimit; if (stackLimit <= stackBase) { Address tmp = stackLimit; stackLimit = stackBase; stackBase = tmp; } ClrAppDomain domain = GetAppDomainByAddress(thread.AppDomain); ClrHeap heap = GetHeap(); var mask = ((ulong)(PointerSize - 1)); var cache = MemoryReader; cache.EnsureRangeInCache(stackBase); for (Address stackPtr = stackBase; stackPtr < stackLimit; stackPtr += (uint)PointerSize) { Address objRef; if (cache.ReadPtr(stackPtr, out objRef)) { // If the value isn't pointer aligned, it cannot be a managed pointer. if (heap.IsInHeap(objRef)) { ulong mt; if (heap.ReadPointer(objRef, out mt)) { ClrType type = null; if (mt > 1024) { type = heap.GetObjectType(objRef); } if (type != null && !type.IsFree) { yield return(new LocalVarRoot(stackPtr, objRef, type, domain, thread, false, true, false)); } } } } } }
/// <summary> /// Returns a ClrObject for this value. /// </summary> /// <returns>A ClrObject for this value. If the value is null, then ClrObject.IsNull will the true and ClrObject.Type /// will equal ClrHeap.ErrorType.</returns> public virtual ClrObject AsObject() { if (!ClrRuntime.IsObjectReference(ElementType)) { throw new InvalidOperationException("Value is not an object."); } if (IsNull) { throw new NullReferenceException(); } ClrHeap heap = Runtime.GetHeap(); ulong obj = Object; return(new ClrObject(obj, obj != 0 ? heap.GetObjectType(obj) : heap.NullType)); }
/// <summary> /// Constructor. /// </summary> /// <param name="heap">A ClrHeap to add objects from.</param> public ObjectSet(ClrHeap heap) { _heap = heap; _minObjSize = heap.PointerSize * 3; _segments = new HeapHashSegment[_heap.Segments.Count]; for (int i = 0; i < _segments.Length; i++) { ulong start = _heap.Segments[i].Start; ulong end = _heap.Segments[i].End; _segments[i] = new HeapHashSegment { StartAddress = start, EndAddress = end, Objects = new BitArray(checked ((int)(end - start) / _minObjSize), false) }; } }
/// <summary> /// Gets the given object reference field from this ClrObject. /// </summary> /// <param name="fieldName">The name of the field to retrieve.</param> /// <returns>A ClrObject of the given field.</returns> /// <exception cref="ArgumentException"> /// The given field does not exist in the object. /// -or- /// The given field was not an object reference. /// </exception> public ClrObject GetObjectField(string fieldName) { ClrInstanceField?field = Type.GetFieldByName(fieldName); if (field is null) { throw new ArgumentException($"Type '{Type.Name}' does not contain a field named '{fieldName}'"); } if (!field.IsObjectReference) { throw new ArgumentException($"Field '{Type.Name}.{fieldName}' is not an object reference."); } ClrHeap heap = Type.Heap; ulong addr = field.GetAddress(Address, _interior); if (!DataReader.ReadPointer(addr, out ulong obj)) { return(default);
private void GetObjSize(ClrHeap heap, ulong obj, out uint count, out ulong size) { // Evaluation stack var eval = new Stack<ulong>(); // To make sure we don't count the same object twice, we'll keep a set of all objects // we've seen before. var considered = new HashSet<ulong>(); count = 0; size = 0; eval.Push(obj); while (eval.Count > 0) { // Pop an object, ignore it if we've seen it before. obj = eval.Pop(); if (!considered.Add(obj)) continue; // Grab the type. We will only get null here in the case of heap corruption. ClrType type = heap.GetObjectType(obj); if (type == null) continue; count++; size += type.GetSize(obj); // Now enumerate all objects that this object points to, add them to the // evaluation stack if we haven't seen them before. type.EnumerateRefsOfObject(obj, (child, offset) => { if (child != 0 && !considered.Contains(child)) eval.Push(child); }); } }
internal static bool GetStaticField(ClrHeap heap, ClrType type, GetMemberBinder binder, out object result) { result = null; bool success = false; ClrStaticField field = null; StringComparison compare = binder.IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture; foreach (var inst in type.StaticFields) { if (inst.Name.Equals(binder.Name, compare)) { field = inst; break; } } if (field != null) { result = new StaticVariableValueWrapper(heap, field); success = true; } return success; }
/// <summary> /// Constructor. /// </summary> /// <param name="heap">A ClrHeap to add objects from.</param> public ObjectSet(ClrHeap heap) { Heap = heap ?? throw new ArgumentNullException(nameof(heap)); List <HeapHashSegment> segments = new List <HeapHashSegment>(heap.Segments.Length); foreach (ClrSegment seg in heap.Segments) { ulong start = seg.Start; ulong end = seg.End; if (start < end) { segments.Add(new HeapHashSegment { StartAddress = start, EndAddress = end, Objects = new BitArray((int)(end - start) / MinObjSize, false) }); } } _segments = segments.ToArray(); }
public async Task<IEnumerable<object>> Execute(Models.OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { _token = token; _heap = DebuggerSession.Instance.Runtime.GetHeap(); _found = false; var stack = new Stack<ulong>(); foreach (var root in _heap.EnumerateRoots()) { stack.Clear(); stack.Push(root.Object); if (token.IsCancellationRequested) break; GetRefChainFromRootToObject(model.ObjectAddress, stack, new HashSet<ulong>()); if (_found) break; } var enumerable = from address in stack orderby address ascending let type = _heap.GetObjectType(address) select new { Address = address, Type = type.Name, MetadataToken = type.MetadataToken, }; return enumerable.ToList(); }); }
private static void PrintDiagnosticInfo(DataTarget dt, ClrRuntime runtime, ClrHeap heap) { Console.WriteLine("DataTarget Info:"); Console.WriteLine(" ClrVersions: " + String.Join(", ", dt.ClrVersions)); Console.WriteLine(" IsMinidump: " + dt.IsMinidump); Console.WriteLine(" Architecture: " + dt.Architecture); Console.WriteLine(" PointerSize: " + dt.PointerSize); Console.WriteLine(" SymbolPath: " + dt.GetSymbolPath()); Console.WriteLine("ClrRuntime Info:"); Console.WriteLine(" ServerGC: " + runtime.ServerGC); Console.WriteLine(" HeapCount: " + runtime.HeapCount); Console.WriteLine(" Thread Count: " + runtime.Threads.Count); Console.WriteLine("ClrRuntime Modules:"); foreach (var module in runtime.EnumerateModules()) { Console.WriteLine(" {0,26} Id:{1}, {2,10:N0} bytes @ 0x{3:X8}", Path.GetFileName(module.FileName), module.AssemblyId, module.Size, module.ImageBase); } Console.WriteLine("ClrHeap Info:"); Console.WriteLine(" TotalHeapSize: " + heap.TotalHeapSize); Console.WriteLine(" Segments: " + heap.Segments.Count); Console.WriteLine(" Gen0 Size: " + heap.GetSizeByGen(0)); Console.WriteLine(" Gen1 Size: " + heap.GetSizeByGen(1)); Console.WriteLine(" Gen2 Size: " + heap.GetSizeByGen(2)); Console.WriteLine(" Gen3 Size: " + heap.GetSizeByGen(3)); }
public StaticVariableValueWrapper(ClrHeap heap, ClrStaticField field) { m_heap = heap; m_field = field; }
/// <summary> /// Creates a GCRoot helper object for the given heap. /// </summary> /// <param name="heap">The heap the object in question is on.</param> public GCRoot(ClrHeap heap) { _heap = heap ?? throw new ArgumentNullException(nameof(heap)); _maxTasks = Environment.ProcessorCount * 2; }
private static Node FindPathToTarget(ClrHeap heap, ClrRoot root) { ClrType type = heap.GetObjectType(root.Object); if (type == null) return null; List<ulong> refList = new List<ulong>(); List<int> offsetList = new List<int>(); Node curr = new Node(root.Object, type); while (curr != null) { if (curr.Children == null) { refList.Clear(); offsetList.Clear(); curr.Type.EnumerateRefsOfObject(curr.Object, delegate(ulong child, int offset) { if (child != 0) { refList.Add(child); offsetList.Add(offset); } }); curr.Children = refList.ToArray(); curr.Offsets = offsetList.ToArray(); } else { if (curr.Curr < curr.Children.Length) { ulong nextObj = curr.Children[curr.Curr]; int offset = curr.Offsets[curr.Curr]; curr.Curr++; if (m_considered.Contains(nextObj)) continue; m_considered.Add(nextObj); Node next = null; if (m_targets.TryGetValue(nextObj, out next)) { curr.Next = next; next.Prev = curr; next.Offset = offset; while (curr.Prev != null) { m_targets[curr.Object] = curr; curr = curr.Prev; } m_targets[curr.Object] = curr; return curr; } type = heap.GetObjectType(nextObj); if (type != null && type.ContainsPointers) { curr = new Node(nextObj, type, curr); curr.Offset = offset; } } else { curr = curr.Prev; if (curr != null) curr.Next = null; } } } return null; }
public static IEnumerable <dynamic> GetProxies <T>(this ClrHeap heap) { return(GetProxies(heap, typeof(T).FullName)); }
public ParallelObjectSet(ClrHeap heap) : base(heap) { }
public static KcpUserAccount GetKcpUserAccountInfo(ulong KcpUserAccountAddr, ClrType KcpUserAccountType, ClrHeap Heap, string databaseLocation) { KcpUserAccount UserAccountInfo = new KcpUserAccount(); // Get the embedded ProtectedBinary ClrInstanceField KcpProtectedBinaryField = KcpUserAccountType.GetFieldByName("m_pbKeyData"); ulong KcpProtectedBinaryAddr = KcpProtectedBinaryField.GetAddress(KcpUserAccountAddr); ulong KcpProtectedBinaryObjAddr = (ulong)KcpProtectedBinaryField.GetValue(KcpUserAccountAddr); ClrInstanceField EncDataField = KcpProtectedBinaryField.Type.GetFieldByName("m_pbData"); ulong EncDataAddr = EncDataField.GetAddress(KcpProtectedBinaryObjAddr); ulong EncDataArrayAddr = (ulong)EncDataField.GetValue(KcpProtectedBinaryObjAddr); ClrType EncDataArrayType = Heap.GetObjectType(EncDataArrayAddr); int len = EncDataField.Type.GetArrayLength(EncDataArrayAddr); if (len <= 0 || len % 16 != 0) // Small sanity check to make sure everything's ok return null; byte[] EncData = new byte[len]; for (int i = 0; i < len; i++) { EncData[i] = (byte)EncDataArrayType.GetArrayElementValue(EncDataArrayAddr, i); } UserAccountInfo.databaseLocation = databaseLocation; UserAccountInfo.encryptedBlob = EncData; UserAccountInfo.encryptedBlobAddress = (IntPtr)KcpUserAccountType.GetArrayElementAddress(EncDataArrayAddr, 0); UserAccountInfo.encryptedBlobLen = len; return UserAccountInfo; }
public void Execute(CommandExecutionContext context) { if (!String.IsNullOrEmpty(TypeRegex)) { try { new Regex(TypeRegex); } catch (ArgumentException) { context.WriteErrorLine("The regular expression specified for --type is not valid; did you forget to escape regex characters?"); return; } } _heap = context.Runtime.GetHeap(); if (!_heap.CanWalkHeap) { context.WriteErrorLine("The heap is not in a walkable state."); return; } var typeInfos = new Dictionary<ulong, TypeInfo>(); // MT to TypeInfo long totalObjectCount = 0; if (!StatisticsOnly) { context.WriteLine("{0,-20} {1,-20} {2}", "MT", "Address", "Size"); } foreach (var obj in _heap.EnumerateObjectAddresses()) { ulong mt = 0; context.Runtime.ReadPointer(obj, out mt); if (!FilterObject(obj, mt)) continue; var type = _heap.GetObjectType(obj); if (type == null || String.IsNullOrEmpty(type.Name)) continue; var size = type.GetSize(obj); if (!StatisticsOnly) { context.WriteLine("{0,-20:x16} {1,-20:x16} {2,-10}", mt, obj, size); } if (typeInfos.ContainsKey(mt)) { var current = typeInfos[mt]; current.Count += 1; current.Size += size; typeInfos[mt] = current; } else { var objType = _heap.GetObjectType(obj); var objTypeName = objType != null ? objType.Name : "<no name>"; typeInfos.Add(mt, new TypeInfo { Size = size, Count = 1, TypeName = objTypeName }); } ++totalObjectCount; } context.WriteLine("Statistics:"); context.WriteLine("{0,-20} {1,-10} {2,-10} {3}", "MT", "Count", "TotalSize", "Class Name"); foreach (var kvp in (from e in typeInfos orderby e.Value.Size ascending select e)) { context.WriteLine("{0,-20:x16} {1,-10} {2,-10} {3}", kvp.Key, kvp.Value.Count, kvp.Value.Size, kvp.Value.TypeName); } context.WriteLine("Total {0} objects", totalObjectCount); }
internal ClrHandle(Microsoft.Diagnostics.Runtime.Desktop.V45Runtime clr, ClrHeap heap, Microsoft.Diagnostics.Runtime.Desktop.HandleData handleData) { Address obj; Address = handleData.Handle; clr.ReadPointer(Address, out obj); Object = obj; Type = heap.GetObjectType(obj); uint refCount = 0; if (handleData.Type == (int)HandleType.RefCount) { if (handleData.IsPegged != 0) refCount = handleData.JupiterRefCount; if (refCount < handleData.RefCount) refCount = handleData.RefCount; if (Type != null) { if (Type.IsCCW(obj)) { CcwData data = Type.GetCCWData(obj); if (data != null && refCount < data.RefCount) refCount = (uint)data.RefCount; } else if (Type.IsRCW(obj)) { RcwData data = Type.GetRCWData(obj); if (data != null && refCount < data.RefCount) refCount = (uint)data.RefCount; } } RefCount = refCount; } HandleType = (HandleType)handleData.Type; AppDomain = clr.GetAppDomainByAddress(handleData.AppDomain); if (HandleType == HandleType.Dependent) { DependentTarget = handleData.Secondary; DependentType = heap.GetObjectType(handleData.Secondary); } }
public ClrValueImpl(ClrHeap heap) : base(heap.Runtime) { _address = 0; _type = heap.NullType; }
private void CreateRuntime(int clrVersionIndex, string dacLocation) { _runtime = _target.ClrVersions[clrVersionIndex].CreateRuntime(dacLocation); _heap = _runtime.GetHeap(); }
/// <summary> /// Creates a GCRoot helper object for the given heap. /// </summary> /// <param name="heap">The heap the object in question is on.</param> public GCRoot(ClrHeap heap) { Heap = heap ?? throw new ArgumentNullException(nameof(heap)); }
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.EnumerateRefsOfObject(obj, delegate(ulong child, int offset) { if (child != 0 && !considered.Contains(child)) eval.Push(child); }); } return considered; }
private static byte[] ReadBuffer(ClrHeap heap, ulong address, int length) { byte[] buffer = new byte[length]; int byteRead = heap.ReadMemory(address, buffer, 0, buffer.Length); if (byteRead != length) throw new InvalidOperationException(string.Format("Expected to read {0} bytes and actually read {1}", length, byteRead)); return buffer; }
private static void PrintGCHeapInfo(ClrRuntime runtime, ClrHeap heap) { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine("\nGC Heap Information - {0}", runtime.ServerGC ? "Server" : "Workstation"); Console.ResetColor(); var seperator = "-----------------------------------------------------------"; var heapSegmentInfo = from seg in heap.Segments group seg by seg.ProcessorAffinity into g orderby g.Key select new { Heap = g.Key, Size = g.Sum(p => (uint)p.Length) }; foreach (var item in heapSegmentInfo) { Console.WriteLine(seperator); Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WriteLine("Heap {0,2}: {1,12:N0} bytes ({2:N2} MB) in use", item.Heap, item.Size, item.Size / 1024.0 / 1024.0); Console.ResetColor(); Console.WriteLine(seperator); Console.WriteLine("{0,12} {1,12} {2,14} {3,14}", "Type", "Size (MB)", "Committed (MB)", "Reserved (MB)"); Console.WriteLine(seperator); var heapSegments = heap.Segments.Where(s => s.ProcessorAffinity == item.Heap) .OrderBy(s => s.IsEphemeral ? 1 : 0 + (s.IsLarge ? 3 : 2)); foreach (ClrSegment segment in heapSegments) { string type; if (segment.IsEphemeral) type = "Ephemeral"; else if (segment.IsLarge) type = "Large"; else type = "Gen2"; Console.WriteLine("{0,12} {1,12:N2} {2,14:N2} {3,14:N2}", type, (segment.End - segment.Start) / 1024.0 / 1024.0, // This is the same as segment.Length (segment.CommittedEnd - segment.Start) / 1024.0 / 1024.0, (segment.ReservedEnd - segment.Start) / 1024.0 / 1024.0); } } Console.WriteLine(seperator); Console.WriteLine("Total (across all heaps): {0:N0} bytes ({1:N2} MB)", heap.Segments.Sum(s => (long)s.Length), heap.Segments.Sum(s => (long)s.Length) / 1024.0 / 1024.0); Console.WriteLine(seperator); }
internal UnknownType(ClrHeap heap) { m_heap = heap; }
private static void ExamineProcessHeap(ClrRuntime runtime, ClrHeap heap, bool showGcHeapInfo) { if (!heap.CanWalkHeap) { Console.WriteLine("Cannot walk the heap!"); return; } ulong totalStringObjectSize = 0, stringObjectCounter = 0, byteArraySize = 0; ulong asciiStringSize = 0, unicodeStringSize = 0, isoStringSize = 0; //, utf8StringSize = 0; ulong asciiStringCount = 0, unicodeStringCount = 0, isoStringCount = 0; //, utf8StringCount = 0; ulong compressedStringSize = 0, uncompressedStringSize = 0; foreach (var obj in heap.EnumerateObjectAddresses()) { ClrType type = heap.GetObjectType(obj); // If heap corruption, continue past this object. Or if it's NOT a String we also ignore it if (type == null || type.IsString == false) continue; stringObjectCounter++; var text = (string)type.GetValue(obj); var rawBytes = Encoding.Unicode.GetBytes(text); totalStringObjectSize += type.GetSize(obj); byteArraySize += (ulong)rawBytes.Length; VerifyStringObjectSize(runtime, type, obj, text); // Try each encoding in order, so we find the most-compact encoding that the text would fit in byte[] textAsBytes = null; if (IsASCII(text, out textAsBytes)) { asciiStringSize += (ulong)rawBytes.Length; asciiStringCount++; // ASCII is compressed as ISO-8859-1 (Latin-1) NOT ASCII if (IsIsoLatin1(text, out textAsBytes)) compressedStringSize += (ulong)textAsBytes.Length; else Console.WriteLine("ERROR: \"{0}\" is ASCII but can't be encoded as ISO-8859-1 (Latin-1)", text); } // From http://stackoverflow.com/questions/7048745/what-is-the-difference-between-utf-8-and-iso-8859-1 // "ISO 8859-1 is a single-byte encoding that can represent the first 256 Unicode characters" else if (IsIsoLatin1(text, out textAsBytes)) { isoStringSize += (ulong)rawBytes.Length; isoStringCount++; compressedStringSize += (ulong)textAsBytes.Length; } // UTF-8 and UTF-16 can both support the same range of text/character values ("Code Points"), they just store it in different ways // From http://stackoverflow.com/questions/4655250/difference-between-utf-8-and-utf-16/4655335#4655335 // "Both UTF-8 and UTF-16 are variable length (multi-byte) encodings. // However, in UTF-8 a character may occupy a minimum of 8 bits, while in UTF-16 character length starts with 16 bits." //else if (IsUTF8(text, out textAsBytes)) //{ // utf8StringSize += (ulong)rawBytes.Length; // utf8StringCount++; // compressedStringSize += (ulong)textAsBytes.Length; //} else { unicodeStringSize += (ulong)rawBytes.Length; unicodeStringCount++; uncompressedStringSize += (ulong)rawBytes.Length; } } Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine("\n\"System.String\" memory usage info"); Console.ResetColor(); Console.WriteLine("Overall {0:N0} \"System.String\" objects take up {1:N0} bytes ({2:N2} MB)", stringObjectCounter, totalStringObjectSize, totalStringObjectSize / 1024.0 / 1024.0); Console.WriteLine("Of this underlying byte arrays (as Unicode) take up {0:N0} bytes ({1:N2} MB)", byteArraySize, byteArraySize / 1024.0 / 1024.0); Console.WriteLine("Remaining data (object headers, other fields, etc) are {0:N0} bytes ({1:N2} MB), at {2:0.##} bytes per object\n", totalStringObjectSize - byteArraySize, (totalStringObjectSize - byteArraySize) / 1024.0 / 1024.0, (totalStringObjectSize - byteArraySize) / (double)stringObjectCounter); Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine("Actual Encoding that the \"System.String\" could be stored as (with corresponding data size)"); Console.ResetColor(); Console.WriteLine(" {0,15:N0} bytes ({1,8:N0} strings) as ASCII", asciiStringSize, asciiStringCount); Console.WriteLine(" {0,15:N0} bytes ({1,8:N0} strings) as ISO-8859-1 (Latin-1)", isoStringSize, isoStringCount); //Console.WriteLine(" {0,15:N0} bytes ({1,8:N0} strings) are UTF-8", utf8StringSize, utf8StringCount); Console.WriteLine(" {0,15:N0} bytes ({1,8:N0} strings) as Unicode", unicodeStringSize, unicodeStringCount); Console.WriteLine("Total: {0:N0} bytes (expected: {1:N0}{2})\n", asciiStringSize + isoStringSize + unicodeStringSize, byteArraySize, (asciiStringSize + isoStringSize + unicodeStringSize != byteArraySize) ? " - ERROR" : ""); Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine("Compression Summary:"); Console.ResetColor(); Console.WriteLine(" {0,15:N0} bytes Compressed (to ISO-8859-1 (Latin-1))", compressedStringSize); Console.WriteLine(" {0,15:N0} bytes Uncompressed (as Unicode)", uncompressedStringSize); Console.WriteLine(" {0,15:N0} bytes EXTRA to enable compression (1-byte field, per \"System.String\" object)", stringObjectCounter); var totalBytesUsed = compressedStringSize + uncompressedStringSize + stringObjectCounter; var totalBytesSaved = byteArraySize - totalBytesUsed; Console.WriteLine("\nTotal Usage: {0:N0} bytes ({1:N2} MB), compared to {2:N0} ({3:N2} MB) before compression", totalBytesUsed, totalBytesUsed / 1024.0 / 1024.0, byteArraySize, byteArraySize / 1024.0 / 1024.0); Console.WriteLine("Total Saving: {0:N0} bytes ({1:N2} MB)\n", totalBytesSaved, totalBytesSaved / 1024.0 / 1024.0); }
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 HeapIndex(CommandExecutionContext context) { _context = context; _heap = context.Runtime.GetHeap(); }
public MDHeap(ClrHeap heap) { m_heap = heap; }