public override IEnumerable <ClrObject> EnumerateObjects() { bool large = IsLargeObjectSegment; uint minObjSize = (uint)IntPtr.Size * 3; ulong obj = FirstObjectAddress; IDataReader dataReader = _helpers.DataReader; // C# isn't smart enough to understand that !large means memoryReader is non-null. We will just be // careful here. using MemoryReader memoryReader = (!large ? new MemoryReader(dataReader, 0x10000) : null) !; byte[] buffer = ArrayPool <byte> .Shared.Rent(IntPtr.Size * 2 + sizeof(uint)); // The large object heap if (!large) { memoryReader.EnsureRangeInCache(obj); } while (ObjectRange.Contains(obj)) { ulong mt; if (large) { if (dataReader.Read(obj, buffer) != buffer.Length) { break; } mt = Unsafe.As <byte, nuint>(ref buffer[0]); } else { if (!memoryReader.ReadPtr(obj, out mt)) { break; } } ClrType?type = _helpers.Factory.GetOrCreateType(_clrmdHeap, mt, obj); if (type is null) { break; } int marker = GetMarkerIndex(obj); if (marker != -1 && _markers[marker] == 0) { _markers[marker] = obj; } ClrObject result = new ClrObject(obj, type); yield return(result); ulong size; if (type.ComponentSize == 0) { size = (uint)type.StaticSize; } else { uint count; if (large) { count = Unsafe.As <byte, uint>(ref buffer[IntPtr.Size]); } else { memoryReader.ReadDword(obj + (uint)IntPtr.Size, out count); } // Strings in v4+ contain a trailing null terminator not accounted for. if (_clrmdHeap.StringType == type) { count++; } size = count * (ulong)type.ComponentSize + (ulong)type.StaticSize; } size = ClrmdHeap.Align(size, large); if (size < minObjSize) { size = minObjSize; } obj += size; obj = _clrmdHeap.SkipAllocationContext(this, obj); } ArrayPool <byte> .Shared.Return(buffer); }