Дамп только корневых управляемых объектов и/или статистики по ним внутри WinDbg

Моя проблема в том, что dumpheap -stat возвращает очень много объектов, и я понятия не имею, какие из них укоренены, а какие нет.

Ну, я могу, если я запускаю команду !mroot или !refs для отдельного адреса, но этот подход не очень хорошо масштабируется для тысяч объектов, о которых сообщает dumpheap.

Например, dumpheap -stat содержит следующую строку:

000007fef3d14088    74247      2375904 Microsoft.Internal.ReadLock

Вау, 74 247 экземпляров. Тем не менее, бег

.logopen c:\tmp\2\log.txt;.foreach (entry {!dumpheap -type Microsoft.Internal.ReadLock -short}){!refs ${entry} -target};.logclose

показывает, что каждый случай, о котором сообщает DumpHeap, на самом деле является неутилизированным мусором!

Как я обнаружил, что каждый экземпляр является мусором, это еще одна проблема. Мне пришлось извлечь все NONE строк в один файл и все Objects referencing строк в другой, а затем сравнить количество строк в каждом файле. Наверняка есть лучший способ :-(.

В любом случае, я хотел бы знать, как сосредоточиться только на корневых объектах. В идеале я хотел бы получить статистику, а также подробную информацию о таких объектах.


person mark    schedule 24.12.2013    source источник
comment
Я предлагаю написать Стиву Джонсону (автору SOSEX) электронное письмо с просьбой указать опции -short для !refs и !mroot, аналогичные !dumpheap -short, чтобы их можно было использовать в дальнейшей обработке.   -  person Thomas Weller    schedule 25.12.2013


Ответы (1)


Ваш цикл по всем объектам уже великолепен, просто команду !refs нужно заменить чем-то другим, которое находит только корневые объекты. В моем примере используются строки, потому что у меня нет приложения, использующего ReadLocks.

Есть два возможных вывода команды !refs. Ссылочный объект выводит, например.

Objects referencing 02703f18 (System.String):
follow 02703a88       128   System.Globalization.NumberFormatInfo

Мусорные объекты выглядят так:

Objects referencing 02703f30 (System.String):
NONE

Вас интересует только адрес первой строки, если вторая строка содержит слово «следует». К счастью, адрес равен ${entry}, поэтому он нам фактически не нужен. В противном случае вы оказались бы в те же проблемы, что и я я.

Это подводит меня к этому вопросу о .if.

Вы можете снова использовать .foreach для вывода !refs. Давайте сначала посмотрим на это на одном объекте:

.foreach (reftoken {!refs 027045cc -target}) { .printf "${reftoken}\n" }

Это печатает по одному слову в строке и нас интересует только пятая, а это значит, что мы можем изначально пропустить 4 элемента, а затем пропустить остальные, что дает нам

.foreach /pS 4 /ps 3 (reftoken {!refs 027045cc -target}) { .printf "${reftoken}\n" }

В целях надежности давайте использовать /ps 99.
Далее нам нужно проверить, равен ли этот токен follow, что делается с помощью

.if ($sicmp("${reftoken}","follow") == 0) { .echo found follow }

И объедините все вместе:

.foreach (entry {!dumpheap -type System.String -short})
{
   .foreach /pS 4 /ps 99 (reftoken {!refs ${entry} -target}) 
   { 
      .if ($sicmp("${reftoken}","follow") == 0) 
      { 
            .printf "${entry}\n"
      } 
   }
}

В одной строке:

 .foreach (entry {!dumpheap -type System.String -short}){.foreach /pS 4 /ps 99 (reftoken {!refs ${entry} -target}) {.if ($sicmp("${reftoken}","follow") == 0) {.printf "${entry}\n"}}}

Конечно, вы можете заменить .print любой другой командой, которая будет полезна в вашей ситуации.

Надеюсь, вы сможете адаптировать этот пример для использования ReadLock.

person Thomas Weller    schedule 27.12.2013
comment
Это отличный ответ. Но мне нужно небольшое пояснение. Что такое $sicmp? Это указатель на функцию сравнения строк из ЭЛТ? Можете ли вы показать, как вы устанавливаете его значение? - person mark; 30.12.2013
comment
$iscmp() — это оператор (функция) MASM, который ведет себя как Win32 stricmp(). См. .hh MASM для других функций. Первый параметр "${reftoken}" создается командой .foreach. - person Thomas Weller; 31.12.2013