Пример #1
0
        public StringSummary GetStringSummary(Action <double> progressCallback = null, CancellationToken token = default)
        {
            var tallyByString = new Dictionary <string, ObjectTally>();

            ulong stringCount                 = 0;
            ulong stringByteCount             = 0;
            ulong totalManagedObjectCount     = 0;
            ulong totalManagedObjectByteCount = 0;
            long  charCount = 0;

            for (var i = 0; i < _heap.Segments.Count; i++)
            {
                progressCallback?.Invoke((double)i / _heap.Segments.Count);

                var seg     = _heap.Segments[i];
                var segType = seg.IsEphemeral
                    ? GCSegmentType.Ephemeral
                    : seg.IsLarge
                        ? GCSegmentType.LargeObject
                        : GCSegmentType.Regular;

                for (ulong obj = seg.GetFirstObject(out ClrType type); obj != 0; obj = seg.NextObject(obj, out type))
                {
                    if (type == null)
                    {
                        continue;
                    }

                    token.ThrowIfCancellationRequested();

                    int generation = seg.GetGeneration(obj);

                    var size = type.GetSize(obj);

                    totalManagedObjectCount++;
                    totalManagedObjectByteCount += size;

                    if (type.IsString)
                    {
                        var value = (string)type.GetValue(obj);

                        charCount += value.Length;
                        stringCount++;

                        if (!tallyByString.TryGetValue(value, out var tally))
                        {
                            tally = new ObjectTally(size);
                            tallyByString[value] = tally;
                        }

                        stringByteCount += tally.InstanceSize;
                        tally.Add(obj, segType, generation);
                    }
                }
            }

            progressCallback?.Invoke(1.0);

            var uniqueStringCount     = tallyByString.Count;
            var stringCharCount       = tallyByString.Sum(s => s.Key.Length * (long)s.Value.Count);
            var uniqueStringCharCount = tallyByString.Keys.Sum(s => s.Length);
            var wastedBytes           = tallyByString.Values.Sum(t => (long)t.WastedBytes);
            var stringOverhead        = ((double)stringByteCount - (charCount * 2)) / stringCount;

            return(new StringSummary(
                       tallyByString.OrderByDescending(p => p.Value.WastedBytes)
                       .Select(
                           p => new StringItem(
                               p.Key,
                               (uint)p.Key.Length,
                               p.Value.InstanceSize,
                               p.Value.Addresses,
                               p.Value.CountBySegmentType,
                               p.Value.CountByGeneration)).ToList(),
                       totalManagedObjectByteCount,
                       stringByteCount,
                       (ulong)stringCharCount,
                       (ulong)uniqueStringCharCount,
                       stringCount,
                       (ulong)uniqueStringCount,
                       totalManagedObjectCount,
                       (ulong)wastedBytes,
                       (uint)Math.Round(stringOverhead)));
        }
Пример #2
0
        public StringSummary GetTypeReferenceStringSummary(ClrType referrerType, int fieldOffset, CancellationToken token = default)
        {
            var tallyByString = new Dictionary <string, ObjectTally>();

            ulong stringCount                 = 0;
            ulong stringByteCount             = 0;
            ulong totalManagedObjectByteCount = 0;
            long  charCount = 0;

            foreach (var seg in _heap.Segments)
            {
                var segType = seg.IsEphemeral
                    ? GCSegmentType.Ephemeral
                    : seg.IsLarge
                        ? GCSegmentType.LargeObject
                        : GCSegmentType.Regular;

                for (ulong refObj = seg.GetFirstObject(out ClrType referringType); refObj != 0; refObj = seg.NextObject(refObj, out referringType))
                {
                    if (referringType == null)
                    {
                        continue;
                    }

                    totalManagedObjectByteCount += referringType.GetSize(refObj);

                    if (!ReferenceEquals(referringType, referrerType))
                    {
                        continue;
                    }

                    token.ThrowIfCancellationRequested();

                    if (!_heap.ReadPointer(refObj + (ulong)fieldOffset, out var strObjRef) || strObjRef == 0)
                    {
                        continue;
                    }

                    var type = _heap.GetObjectType(strObjRef);
                    if (type == null)
                    {
                        continue;
                    }
                    var value = (string)type.GetValue(strObjRef);

                    charCount += value.Length;
                    stringCount++;

                    if (!tallyByString.TryGetValue(value, out var tally))
                    {
                        var size = type.GetSize(strObjRef);
                        tally = new ObjectTally(size);
                        tallyByString[value] = tally;
                    }

                    var strSeg     = _heap.GetSegmentByAddress(strObjRef);
                    int generation = strSeg.GetGeneration(strObjRef);
                    if (tally.Add(strObjRef, segType, generation))
                    {
                        stringByteCount += tally.InstanceSize;
                    }
                }
            }

            var uniqueStringCount     = tallyByString.Count;
            var stringCharCount       = tallyByString.Sum(s => s.Key.Length * (long)s.Value.Count);
            var uniqueStringCharCount = tallyByString.Keys.Sum(s => s.Length);
            var wastedBytes           = tallyByString.Values.Sum(t => (long)t.WastedBytes);
            var stringOverhead        = ((double)stringByteCount - (charCount * 2)) / stringCount;

            return(new StringSummary(
                       tallyByString.OrderByDescending(p => p.Value.WastedBytes)
                       .Select(
                           p => new StringItem(
                               p.Key,
                               (uint)p.Key.Length,
                               p.Value.InstanceSize,
                               p.Value.Addresses,
                               p.Value.CountBySegmentType,
                               p.Value.CountByGeneration)).ToList(),
                       totalManagedObjectByteCount,
                       stringByteCount,
                       (ulong)stringCharCount,
                       (ulong)uniqueStringCharCount,
                       stringCount,
                       (ulong)uniqueStringCount,
                       ulong.MaxValue, // TODO review
                       (ulong)wastedBytes,
                       (uint)Math.Round(stringOverhead)));
        }