我的问题是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
字符串提取到另一个文件,然后比较每个文件中的行数。当然有更好的方法: - (。
无论如何,我想知道如何只专注于有根的对象。理想情况下,我想获得有关此类对象的统计数据和详细信息。
答案 0 :(得分:4)
你对所有对象的循环已经很好了,只需要将!refs命令替换为只找到有根对象的其他东西。我的示例使用了Strings,因为我没有使用ReadLocks提供的应用程序。
!refs命令有两种可能的输出。引用的对象输出例如
Objects referencing 02703f18 (System.String):
follow 02703a88 128 System.Globalization.NumberFormatInfo
垃圾对象如下所示:
Objects referencing 02703f30 (System.String):
NONE
如果第二行包含单词“follow”,您只对第一行的地址感兴趣。幸运的是,地址等于${entry}
,所以我们实际上并不需要它。否则你会进入same trouble like I am。
这将我带到this question about .if。
你可以在!refs的输出上再次使用.foreach。让我们先在一个对象上看一下这个:
.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。