如何识别仍然引用对象的实例?

时间:2011-04-28 12:45:38

标签: c# .net

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

实例数 ---------- 1 418 276
总实例百分比---------------------%5.8
分配的总字节数------- 158 846 912
%总字节数--------------------------%5.94
Gen 0实例收集--------- 5 196
第1组实例收集-------- 54 894
第二代实例收集 ---- 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,他们仍然被引用到某个地方,但如何确定?我厌倦了猜测和尝试这么多的假设,如果有人有更合理的指导方针或公平的清单和/或工具/精确的探查器的地方,我欢迎它。

答案的补充资源
Visual GCRoot via DGML - 感谢Richard Szalay 此外,Chris Lovett的这段视频GCRoot Demo对这个主题非常有教育意义。

3 个答案:

答案 0 :(得分:7)

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

    这将返回如下内容:

     Address       MT     Size
    026407c0 53ecee20       16     
    

    然后,您可以使用Address并使用GCRoot查找其根源所在的位置:

    !GCRoot 026407c0
    

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

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

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

答案 1 :(得分:2)

EDIT 2018:如果你有2015 +视觉工作室,那么整个过程就会简单得多:MSDN tutorial

如果您想确切知道哪些实例存活,您需要做的就是使用debugging tools for windows附带的Adplus进行流程转储。 (它现在是SDK下载的一部分。)

然后在WinDBG中,使用!dumpheap -type 命令查看哪些类仍处于什么状态。

然后您可以使用!gcroot查看谁持有该引用。

答案 2 :(得分:-1)

您可以键入命令gcroot