У меня есть действительно большие дампы памяти управляемого процесса, из которых я пытаюсь получить много статистики, а также иметь возможность представить интерактивное представление довольно глубоких графов объектов в куче. Подумайте о чем-то похожем на !do <address>
с prefer_dml 1
, установленным в WinDbg с SOS, где вы можете постоянно нажимать на свойства и видеть их значения, только в гораздо более удобном пользовательском интерфейсе для сравнения многих объектов.
Я обнаружил, что Microsoft.Diagnostics.Runtime (ClrMD) особенно хорошо подходит для этой задачи, но мне трудно работать с полями массива, и я немного запутался в полях объектов. , который у меня работает немного лучше.
Массив: если я нацеливаюсь на массив с адресом непосредственно из кучи и использую ClrType.GetArrayLength
и ClrType.GetArrayElementValue
, все работает нормально, но как только я копаюсь в полях другого объекта, я не уверен, какое значение Я получаю от ClrInstanceField.GetValue
, когда ClrInstanceField.ElementType
равно ClrElementType.SZArray
(я еще не сталкивался с Array
, копающимся в моем графе объектов, но я также хотел бы справиться с этим).
Редактировать: я просто решил использовать ClrType
вместо System.UInt64
для разыменования поля массива (используя parent address + offset of the array field
для вычисления адреса, где хранится указатель массива), после чего я могу работать с это так же, как если бы я получил его от EnumerateObjects. Теперь у меня возникли трудности с некоторыми массивами, не поддерживающими свойство ArrayComponentType
. Мне еще предстоит протестировать массивы структур, поэтому мне также интересно, будет ли это выделение встроенных структур в стиле C, как с int[]
, или это будет массив указателей на структуры в куче. Guid[]
— это один из типов, из которых у меня возникли проблемы с получением ArrayComponentType
.
Объект: Исправлено (логическая ошибка) С ClrInstanceField
, у которого Type
из ClrElementType.Object
, я получаю гораздо лучшие результаты, но все же нужно немного больше. Во-первых, после вызова GetFieldValue
я получаю обратно адрес ulong
(?), против которого я могу использовать ClrInstanceField.Type.Fields
, так что я могу видеть имена полей и значения вложенного объекта. Тем не менее, я должен учитывать полиморфизм, поэтому я попытался использовать ClrHeap.GetObjectType
по тому же адресу, и он либо возвращает NULL, либо что-то совершенно неправильное. Кажется странным, что адрес сработал в моем первом случае, но не во втором.
Строка: Исправлено (найден обходной путь) Поскольку мой реальный проект уже использует DbgEng с SOS, у меня есть другой способ легко получить значение строки по адресу, но показалось очень странным, что при попытке использовать ClrInstanceField.GetFieldValue
удалось вернуть строку, но с совершенно неточными результатами (куча странных символов). Может я что-то не так делаю?
Изменить: я извлек абстракцию, которая теперь работает в LINQPad, из исходного кода. Публиковать здесь немного долго, но все вкратце . Это все еще немного запутано из-за всего копирования/вставки/рефакторинга, и я буду чистить его дальше и, вероятно, опубликую окончательный исходный код либо на CodePlex, либо на GitHub после того, как я исправлю эти проблемы.
База кода довольно велика и специфична для проекта, но если это абсолютно необходимо, я могу извлечь набор примеров. Тем не менее, любой доступ к объектам ClrMD довольно прост. Я получаю начальные адреса из команд SOS, таких как !dumpheap -stat
(что прекрасно работает для корневых объектов), а затем использую ClrHeap.GetTypeByName
или ClrHeap.GetObjectType
. После этого он полагается исключительно на ClrType.Fields
и ClrInstanceField
членов Type
, ElementType
и GetFieldValue
В качестве дополнительного бонуса я нашел дружественный к браузеру версия документов XML, поставляемая с пакетом NuGet, хотя это та же документация, которую предоставляет IntelliSense.