Сброс только корневых управляемых объектов и / или статистики по ним внутри 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
строк в другой, а затем сравнил количество строк в каждом файле. Конечно, есть лучший способ:-(.
Во всяком случае, я хотел бы знать, как сосредоточиться только на корневых объектах. В идеале я хотел бы получить статистику, а также подробную информацию о таких объектах.
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
,
Далее нам нужно проверить, равен ли этот токен следующим образом, что делается
.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.