in src/Microsoft.Diagnostics.Runtime/ClrHeap.cs [362:428]
internal IEnumerable<ClrObject> EnumerateObjects(ClrSegment segment, ulong startAddress, bool carefully)
{
if (!segment.ObjectRange.Contains(startAddress))
yield break;
uint pointerSize = (uint)_memoryReader.PointerSize;
uint minObjSize = pointerSize * 3;
uint objSkip = segment.Kind != GCSegmentKind.Large ? minObjSize : 85000;
using MemoryCache cache = new(_memoryReader, segment);
ulong obj = GetValidObjectForAddress(segment, startAddress);
while (segment.ObjectRange.Contains(obj))
{
if (!cache.ReadPointer(obj, out ulong mt))
{
if (!carefully)
break;
obj = FindNextValidObject(segment, pointerSize, obj + objSkip, cache);
continue;
}
ClrType? type = _typeFactory.GetOrCreateType(mt, obj);
ClrObject result = new(obj, type ?? ErrorType);
yield return result;
if (type is null)
{
if (!carefully)
break;
obj = FindNextValidObject(segment, pointerSize, obj + objSkip, cache);
continue;
}
SetMarkerIndex(segment, obj);
ulong size;
if (type.ComponentSize == 0)
{
size = (uint)type.StaticSize;
}
else
{
if (!cache.ReadUInt32(obj + pointerSize, out uint count))
{
if (!carefully)
break;
obj = FindNextValidObject(segment, pointerSize, obj + objSkip, cache);
continue;
}
// Strings in v4+ contain a trailing null terminator not accounted for.
if (StringType == type)
count++;
size = count * (ulong)type.ComponentSize + (ulong)type.StaticSize;
}
size = Align(size, segment);
if (size < minObjSize)
size = minObjSize;
obj += size;
obj = SkipAllocationContext(segment, obj);
}
}