Сброс только корневых управляемых объектов и / или статистики по ним внутри 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.

Другие вопросы по тегам