在WinDbg中查看根对象

在WinDbg中查看根对象,windbg,sos,Windbg,Sos,我正在尝试使用WinDbg调查.NET中的内存泄漏 然而,当我试图检查的输出时!dumpheap-type我看到,如果不是所有列出的对象都是“自由”对象的话,那么也有很多。我想过滤列表,看看是否有根目录(有对它们的引用) 我尝试了以下脚本: .foreach (t {!dumpheap -mt 0000000091ea94f0 -short}) { .if(!gcroot ${t}) { !mdt ${t} } } 但是,它不输出任何内容。有没有办法过滤掉的输出!dumpheap是否仅显示根对

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

然而,当我试图检查
的输出时!dumpheap-type
我看到,如果不是所有列出的对象都是“自由”对象的话,那么也有很多。我想过滤列表,看看是否有根目录(有对它们的引用)

我尝试了以下脚本:

.foreach (t {!dumpheap -mt 0000000091ea94f0 -short}) { .if(!gcroot ${t}) { !mdt ${t} } }
但是,它不输出任何内容。有没有办法过滤掉
的输出!dumpheap
是否仅显示根对象?

释放“对象” .NET使用堆管理器跟踪内存。这使得分配小于64 kB的对象成为可能,其中64 kB是操作系统提供的最小内存

因此,.NET至少获得64 kB,然后将其拆分为更小的部分。那些未使用的部件可以理解为
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
跳过第一个单词(“找到”),然后处理一个单词,然后使用
/pS 99
跳过其余的单词(实际上最多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}
整个脚本(格式化为可读性,删除换行符和缩进):

在您的情况下,用
替换
.echo something
!mdt${t}

PyKd
因为上面的脚本很难理解并且容易出错,所以您可能需要尝试PyKD。查找
dbgCommand()
以执行调试器命令并将结果作为字符串获取。然后,您可以使用任何Python命令对该字符串进行操作,这比WinDbg内置函数容易得多。

回答得很好,但如果您计划运行
,我强烈建议您使用sosex!gcroot
在一个大内存转储上执行多次。sosex可以构建一个堆索引,使其引用搜索命令运行得更快。
.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
        }
     }
 }