Как отобразить управляемые объекты с определенным значением в одном из полей WinDbg с помощью SOS (или SOSEX)?


Моя проблема такова:

0:000> !DumpHeap -type Microsoft.Internal.ReadLock -stat
------------------------------
Heap 0
total 0 objects
------------------------------
Heap 1
total 0 objects
------------------------------
Heap 2
total 0 objects
------------------------------
Heap 3
total 0 objects
------------------------------
total 0 objects
Statistics:
              MT    Count    TotalSize Class Name
000007fef3d14088    74247      2375904 Microsoft.Internal.ReadLock
Total 74247 objects

Способ, которым я читаю этот вывод, заключается в том, что у меня есть 74 247 экземпляров Microsoft.Internal.ReadLock в моей куче. Однако некоторые из них, вероятно, еще не собраны.

Я хочу отобразить только те, которые не ожидают сбора.

Например, 0000000080f88e90 - это адрес одного из этих объектов, и это мусор. Я знаю это, потому что:

0:000> !mroot 0000000080f88e90
No root paths were found.
0:000> !refs 0000000080f88e90 -target
Objects referencing 0000000080f88e90 (Microsoft.Internal.ReadLock):
NONE
0:000> !do 0000000080f88e90
Name:        Microsoft.Internal.ReadLock
MethodTable: 000007fef3d14088
EEClass:     000007fef3c63410
Size:        32(0x20) bytes
File:        C:WindowsMicrosoft.NetassemblyGAC_MSILSystem.ComponentModel.Compositionv4.0_4.0.0.0__b77a5c561934e089System.ComponentModel.Composition.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef3d13fb0  400001e        8 ...oft.Internal.Lock  0 instance 0000000080001010 _lock
000007fef0a8c7d8  400001f       10         System.Int32  1 instance                1 _isDisposed

Как можно видеть, и sosex.mroot, и sosex.refs указывают на то, что никто не ссылается на него, плюс сброс его полей показывает, что он был удален через IDisposable, поэтому имеет смысл, что объект является мусором (я знаю, что удаление не означает, что объект является мусором, но это в данном случае).

Теперь я хочу показать все те экземпляры, которые не являются мусором. Я думаю, что должен использовать команду .foreach. Что-то вроде этого:
.foreach(entry {!dumpheap -type Microsoft.Internal.ReadLock -short}){.if (???) {.printf "%pn", entry} }
Моя проблема в том, что я понятия не имею, что входит в условие .if.

Я могу исследовать поле _isDisposed следующим образом:

0:000> dd 0000000080f88e90+10 L1
00000000`80f88ea0  00000001

Но .if ожидает выражения, и все, что у меня есть-это вывод команды. Если бы я знал, как извлечь информацию из вывода команды и организовать ее в виде выражения, то я мог бы использовать ее как условие .if и быть хорошим.

Итак, мой вопрос таков-есть ли способ получить значение поля в виде выражения, подходящего для .if? Кроме того, можно ли проанализировать выходные данные команды таким образом, чтобы использовать результат в качестве условия .if?
1 5

1 ответ:

У меня не было примера, который использует объекты ReadLock, но я попробовал со строками, и вот мой результат:

.foreach (entry {!dumpheap -short -type Microsoft.Internal.ReadLock}) 
{ 
    .if (poi(${entry}+10) == 1)  
    {
         .printf "%p\n", ${entry}
    }
}

Я использую poi() для получения данных о размере указателя из адреса. Также обратите внимание, что я использую ${entry} Не entry в обоих, poi() и .printf. Вам тоже может понравиться !сделайте ${вход} внутри .если.

В одной строке для копирования / вставки:

.foreach (entry {!dumpheap -short -type Microsoft.Internal.ReadLock}) {.if (poi(${entry}+10) == 1) {.printf "%p\n", ${entry}}}