2

我想从以下命令对每个地址运行 !refs 命令

!dumpgen 2 -type System.DateTime[]

如何做到这一点。我知道可以按如下方式创建一个循环

.foreach (myvar {!dumpgen 2 -type System.DateTime[]}) 

但是我怎样才能访问可以在循环中使用!refs 的对象地址?

4

1 回答 1

3

!dumpgen没有-short像 has 这样的论点!dumpheap,我真的很想看到一个比这个更简单的答案。

方法一:手动转储一代

  1. 获取堆的地址

    0:003> !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x026f1018
    generation 1 starts at 0x026f100c
    generation 2 starts at 0x026f1000
    
  2. 使用地址将输出限制为您想要的一代:

    !dumpheap -type X <start> <end>
    
  3. 使用-short参数 on !dumpheap,它只输出地址。然后可以由其他命令处理对象的此地址。

另请注意: using-type也可能导致其他类型。更好地使用方法表,-mt因为只有这样才能保证类型的唯一性。!name2ee如果您没有从其他地方得到它,请使用它。

一个完整的会话可能如下所示:

0:003> !dumpheap -stat
total 345 objects
Statistics:
      MT    Count    TotalSize Class Name
53ab421c        1           12 System.Text.DecoderExceptionFallback
[...]
53ab0d48      135         6640 System.String
53a84518       26         9452 System.Object[]
Total 345 objects

0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x026f1018
generation 1 starts at 0x026f100c
generation 2 starts at 0x026f1000
[...]

0:003> !name2ee *!System.String
Module: 53841000 (mscorlib.dll)
Token: 0x02000024
MethodTable: 53ab0d48
[...]

0:003> !dumpheap -short -mt 53ab0d48 0x026f1000 0x026f100c

(好吧,我所有的字符串似乎都在第 0 代,该死的 :-)

0:003> .foreach (addr {!dumpheap -short -mt 53ab0d48 0x026f1018}) {!refs ${addr}}

缺点:您需要分别为所有 GC 堆执行此操作。可能有几个。

方法 2:决定每个对象的生成

另一个丑陋的解决方案是

  1. 转储所有对象地址(!dumpheap -short-type-mt
  2. 通过查询每个对象的生成!gcgen
  3. 根据生成,执行命令

以下是如何做到这一点(为便于阅读而格式化,将其全部放在一行中):

.foreach (addr {!dumpheap -short -mt 53ab0d48}) {
    .foreach /pS 1 (gen {!gcgen ${addr}}) { 
        .if ($scmp("${gen}","2")==0) {
            !refs ${addr}
        }
    }
}

53ab0d48您要查找的类型的方法表在哪里,并且"2"是您想要的一代。/pS 1在 的输出中跳过单词“Gen” !gcgen

缺点:可能会很慢,因为它适用于所有对象。

于 2015-11-12T17:12:07.153 回答