如何列出GC终结列表中的所有对象?

4

我的程序出现了崩溃,它是一个用于VS的可视化工具,因此很难调试。我已经尝试过生成转储文件并使用WinDbg进行分析,但都没有成功。

所以现在我想通过编程方式来处理这个列表,但我不知道该怎么做。谢谢。


哪个终结列表?当前所有仍然存活,但(当垃圾收集器不再观察到引用时)将被终结的所有对象的列表,还是已经发生这种情况并且只等待终结器线程访问它们的所有对象的列表? - Damien_The_Unbeliever
2
所以你想要 f-reachable 队列。 - Yuval Itzchakov
@Damien_The_Unbeliever:关于“或者所有已经发生过这种情况并且只等待终结器线程访问它们的对象列表”,就我对.NET GC的理解来说,这似乎没有意义。一个对象的内存可能已经被回收(垃圾回收),但是该对象可能尚未被终结。但是,一个对象已经被终结但“终结器线程尚未访问它”似乎不可能发生。如果终结器线程没有“访问”一个对象,那么该对象就没有被终结。 - stakx - no longer contributing
@stakx - 我的意思是“在这已经发生的地方”,即“当垃圾回收器观察不到更多引用时”。 - Damien_The_Unbeliever
@Damien_The_Unbeliever:这解决了我的疑惑,谢谢。 - stakx - no longer contributing
这是一个非常棘手的 XY 问题。可视化工具永远无法显示处于 finalization 队列中的对象。只有当没有引用时,它才能进入该队列。因此,崩溃与此无关。 - Hans Passant
2个回答

3
如果您想查看对象是否在终结队列或f-reachable队列中,当您启动WinDBG时,请先使用dumpheap -stat或任何其他命令找到您的对象。找到对象的地址后,您可以使用!FinalizeQueue,它将输出每个代中有多少个可终结对象以及有多少个准备终结的对象。前者是终结队列,后者是f-reachable队列。
例如:

0:003> !FinalizeQueue

需要清理的同步块: 0,需要释放的MTA接口: 0,需要释放的STA接口: 0

第0代有370个可终结对象
(0000000000d29030->0000000000d29bc0)

第1代有4个可终结对象
(0000000000d29010->0000000000d29030)

第2代有8个可终结对象
(0000000000d28fd0->0000000000d29010)

准备终结571个对象
(0000000000d29bc0->0000000000d2ad98)

现在,您可以看到对象地址空间在哪里。

这里提供了一个很好的教程。


是的,作为在VS内运行的线程,我可以对所有devenv进程进行转储。但我无法捕捉到制作转储的精确时刻。 - Yola
@Yola 那我不确定你实际上在问什么。 - Yuval Itzchakov
我现在遇到了源代码控制的问题,无法运行所有检查。修复后我会回答你。谢谢,至少关于术语方面的帮助。 - Yola
@Yola 你明白它们的区别了吗? - Yuval Itzchakov
1
没错,我之所以要求f-reachable是因为我认为存在本地资源没有被正确释放的问题。 - Yola
显示剩余2条评论

2
我不认为有一种方法可以通过.NET的托管框架类库(FCL)获取最终化队列。我猜想,如果你想要以编程方式而不是使用WinDbg进行调试,你(就像WinDbg和类似的工具一样)需要使用CLR的非托管调试和分析API来实现这一点。
请查看ICORDebugGCReferenceEnum COM接口。你可以通过ICorDebugProcess5::EnumerateGCReferences获得该类型的对象:
“为将被垃圾回收的对象提供一个枚举器。” “COR_GC_REFERENCE 集合中的对象(通过 ICorDebugGCReferenceEnum::Next 方法 填充)代表三种类型的对象:
  • 来自所有托管堆栈的对象。这包括托管代码中的活动引用以及由公共语言运行时创建的对象。

  • 来自句柄表的对象。这包括模块中的强引用 (HNDTYPE_STRONGHNDTYPE_REFCOUNT) 以及静态变量。

  • 来自终结器队列的对象。终结器队列会在终结器运行之前保留对象的根引用。

(超链接和强调由我添加。)”
枚举器返回的每个对象都有一个字段type。您可能想要过滤出该字段值匹配CorGCReferenceType.CorReferenceFinalizer的对象。

感谢您提供这个方向,我不太清楚如何使用我在 WDK 目录下找到的 cordebug.idl 和 cordebug.tlb 文件,也许您可以提供任何有关如何使用此类对象的链接? - Yola
1
@Yola:那是一个完全不同的问题,我相信这个问题以前已经被问过了。我建议你在SO或者网上搜索一下。无论如何,我不确定.NET进程是否可以检查自己的运行时(我从未尝试过),但如果你想使用.NET来做到这一点,这里有一个提示:使用tlbimp工具从.tlb生成一个带有COM互操作类型的.NET“主要互操作程序集”。 - stakx - no longer contributing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接