Поиск данных экземпляра типа в куче.net
Допустим, у меня есть два класса Foo и Bar следующим образом
public class Foo
{
private Bar _bar;
private string _whatever = "whatever";
public Foo()
{
_bar = new Bar();
}
public Bar TheBar
{
get
{
return _bar;
}
}
}
public class Bar
{
public string Name { get; set; }
}
У меня есть приложение, которое подключается к процессу, который использует эти классы. Я хотел бы видеть все экземпляры типа Foo в куче.NET и проверить свойство TheBar.Name или поле _whwh всех экземпляров Foo, присутствующих в куче.NET. Я могу найти тип, но я не уверен, как получить экземпляр и увидеть его свойства. Есть идеи как?
using (DataTarget target = DataTarget.AttachToProcess(processId, 30000))
{
string dacLocation = target.ClrVersions[0].TryGetDacLocation();
ClrRuntime runtime = target.CreateRuntime(dacLocation);
if (runtime != null)
{
ClrHeap heap = runtime.GetHeap();
foreach (ulong obj in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(obj);
if (type.Name.Compare("Foo") == 0 )
{
// I would like to see value of TheBar.Name property or _whatever field of all instances of Foo type in the heap. How can I do it?
}
}
}
}
3 ответа
Я не думаю, что вы можете получить значения свойств напрямую, потому что это потребует от вас выполнения кода, и целью может быть даже не процесс, а файл дампа.
Вы можете определенно получить поля объекта и их значения. ClrType имеет свойство Fields, которое вы можете использовать для циклического перемещения по полям. Затем вы можете вызвать GetFieldValue для полей, в которых значение HasSimpleValue равно true.
Простой пример:
private static void PrintFieldsForType(ClrRuntime runtime, string targetType)
{
ClrHeap heap = runtime.GetHeap();
foreach (var ptr in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(ptr);
if (type.Name == targetType)
{
foreach(var field in type.Fields)
{
if (field.HasSimpleValue)
{
object value = field.GetFieldValue(ptr);
Console.WriteLine("{0} ({1}) = {2}", field.Name, field.Type.Name, value);
}
else
{
Console.WriteLine("{0} ({1})", field.Name, field.Type.Name);
}
}
}
}
}
Таким образом, вы можете найти поле, в котором есть "Имя", "_имя" или что-то подобное. Если это автоматически реализованное свойство, имя будет примерно таким <Name>k__BackingField
,
Ваш сценарий немного сложнее, потому что вы хотите перейти к другому объекту. Для этого мы можем рекурсивно проверить поля. Тем не менее, обратите внимание, что в общем случае вы бы хотели отслеживать, какие объекты вы посетили, чтобы не повторять бесконечно.
Вот пример, который больше подходит для этого:
private static void PrintFieldsForType(ClrRuntime runtime, TextWriter writer, string targetType)
{
ClrHeap heap = runtime.GetHeap();
foreach (var ptr in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(ptr);
if (type.Name == targetType)
{
writer.WriteLine("{0}:", targetType);
PrintFields(type, writer, ptr, 0);
}
}
}
private static void PrintFields(ClrType type, TextWriter writer, ulong ptr, int indentLevel)
{
string indent = new string(' ', indentLevel * 4);
foreach (var field in type.Fields)
{
writer.Write(indent);
if (field.IsObjectReference() && field.Type.Name != "System.String")
{
writer.WriteLine("{0} ({1})", field.Name, field.Type.Name);
ulong nextPtr = (ulong)field.GetFieldValue(ptr);
PrintFields(field.Type, writer, nextPtr, indentLevel + 1);
}
else if (field.HasSimpleValue)
{
object value = field.GetFieldValue(ptr);
writer.WriteLine("{0} ({1}) = {2}", field.Name, field.Type.Name, value);
}
else
{
writer.WriteLine("{0} ({1})", field.Name, field.Type.Name);
}
}
}
Вот как вы можете сделать это в LINQPad с ClrMD.Extensions:
var session = ClrMDSession.AttachToProcess(processId);
session.EnumerateClrObjects("*Foo").Dump(depth:3);
Я не знаю, можно ли запросить кучу таким способом. но простое решение - сделать что-то вроде этого:
public class Foo
{
public static List<WeakReference<Foo>> allInstances = new List<WeakReference<Foo>>();
public Foo()
{
allInstances.Add(new WeakReference<Foo>(this));
}
}
Обязательно оберните затем в WeakReference, чтобы ваша коллекция не оставляла их в куче, пока процесс не завершится.