在WinDbg中查看有根对象

时间:2015-07-27 19:32:24

标签: windbg sos

我正在尝试使用WinDbg调查.NET中的内存泄漏。

然而,当我尝试检查!dumpheap -type的输出时,我发现很多(如果不是所有)列出的对象都是“Free”对象。我想过滤列表以查看是否有任何根源(引用它们)。

我尝试了以下脚本:

.foreach (t {!dumpheap -mt 0000000091ea94f0 -short}) { .if(!gcroot ${t}) { !mdt ${t} } }

但是,它不会输出任何内容。有没有办法过滤掉!dumpheap的输出以仅显示有根对象?

1 个答案:

答案 0 :(得分:2)

免费“对象”

.NET使用堆管理器来跟踪内存。这使得可以分配小于64 kB的对象,其中64 kB是OS提供的最小内存。

因此,.NET获得至少64 kB,然后将其拆分为更小的部分。那些未使用的部分可以理解为Free类型的对象。

要更好地了解Free个对象,请使用!dumpheap -stat -type Free。那些Free对象没有根,因为它们实际上不是对象。

但你也可以看到很多其他物品,包括它们的大小总和。这些很可能是根深蒂固的。

生根对象

不幸的是,像!gcroot这样的命令没有布尔返回值,所以你需要使用一些棘手的东西。基本的.foreach循环已经非常好了。

要获得可比较的返回值,我们将使用根计数,在以下情况下为1

0:004> !gcroot 02701078
HandleTable:
    001f11ec (strong handle)
    -> 02701078 System.OutOfMemoryException

Found 1 unique roots (run '!GCRoot -all' to see all roots).

由于数字可以是1,2,3等,因此检查!=0似乎更可靠。让我们这样开始:

.shell -ci"!gcroot ${t}" find "Found 0"

这只会保留一行“找到0个唯一的根...”,否则什么都没有。

然后让我们最小化输出只是为了通过使用/pS 1跳过第一个单词(“Found”)来保持数字,然后处理一个单词然后使用{{跳过其余单词(实际上最多99个单词) 1}}:

/ps 99

这将只留下.foreach /pS 1 /ps 99(word {.shell -ci"!gcroot ${t}" find "Found 0"}) {.echo ${word}}

接下来,使用0可以比较字符串:

$scmp()

整个脚本(格式化为可读性,删除换行符和缩进):

.if ($scmp("${word}","0")==0) {.echo nothing} .else {.echo something}

在您的情况下,请将.foreach (t {!dumpheap -short -mt 70c240b4}) { .foreach /pS 1 /ps 99 (word {.shell -ci"!gcroot ${t}" find "Found 0"}) { .if ($scmp("${word}","0")==0){ .echo nothing } .else { .echo something } } } 替换为.echo something

PyKd

由于上述脚本难以理解且容易出错,因此您可能需要尝试PyKD。查找!mdt ${t}以执行调试器命令并将结果作为字符串获取。然后,您可以使用任何Python命令对该字符串进行操作,这比WinDbg内置函数更容易。