如何识别对象的实例仍在引用的位置?

在我的应用程序中使用对象生命周期跟踪运行VS2010探查器后,我在特定的类上有这个:

实例数 ———- 1 418 276
%总实例———————%5.8
分配的总字节数——- 158 846 912
%总字节数————————–%5.94
第0代实例收集——— 5 196
第1组实例收集——– 54 894
第2组实例收集 —- 747 874
最后活动 ——— 610 312
Gen 0字节收集———– 581 952
Gen 1 Bytes Collected ——— 6 148 128
Gen 2 Bytes Collected ——— 3 761 888

正如你所看到的, 所有创建的实例中有一半最终主要是第2代 ,而另一半则一直活着直到应用程序结束 。 [ ha,ha,ha,ha,活着,活着…… – > 对不起,我无法抗拒…… ]

困扰我的是这些实例的生命周期非常短(它基本上是一个数据域类 – 可能是一个结构体,但我更喜欢使它成为一个“激活”GC的类)。
这些实例是通过读取非常大的二进制文件(每行是一个类/一个记录)创建的,并通过委托/事件通过一个小型队列传递给基本上只是读取它的工作者,将它放入队列( 非常经常出列) ,然后终止(后台工作人员正常结束)。 我想当工人不再存在时,事件是取消订阅的。

那么, 有没有办法确定这些引用隐藏在哪里 ? 因为如果他们不是GC,他们仍然被引用到某个地方,但如何确定? 我厌倦了猜测和尝试这么多的假设,如果有人有更合理的指导方针或公平的清单和/或工具/精确的探查器的地方,我欢迎它。

答案的补充资源
通过DGML进行Visual GCRoot – 感谢Richard Szalay
此外,Chris Lovett的这部videoGCRoot Demo对这个主题非常有教育意义。

  1. 在项目属性的“调试”选项卡中启用非托管调试
  2. 运行应用程序并在要调查类型的位置设置断点
  3. 立即窗口中,键入:
.load sos !DumpHeap -type  

这将返回如下内容:

  Address MT Size 026407c0 53ecee20 16 

然后你可以获取Address并使用GCRoot查找它的根源:

 !GCRoot 026407c0 

Chris Lovett (来自Tess Ferrandez )创建了一个非常简洁的实用程序,可将低级GCRoot输出转换为DGML图,这可能使其更容易诊断。

或者,Mohamed Mahmoud创建了一个调试器扩展 ,使您可以从WinDBG生成图形,但它在Visual Studio中不起作用,因此您可能希望坚持使用Chris的实用程序来避免安装调试工具。

话虽如此,文本输出可能足以让您跟踪事情。 如果您需要有关GCRoot输出的信息, !help GCRoot在即时窗口中键入!help GCRoot

编辑2018:如果您有2015 +视觉工作室,那么整个过程就会简单得多: MSDN教程 。

如果你想确切地知道哪些实例是活着的,你需要做的就是使用Adplus的进程转储,它随windows的调试工具一起提供 。 (它现在是SDK下载的一部分。)

然后在WinDBG中,使用!dumpheap -type命令查看哪些类仍在运行的实例。

那么你可以使用!gcroot来查看谁持有该引用。

您可以输入命令gcroot