【问题标题】:How to tell what/who is preventing an object from being garbage collected (C#)如何判断是什么/谁在阻止对象被垃圾收集(C#)
【发布时间】:2015-04-22 18:21:48
【问题描述】:

我已经在 C#/WPF 应用程序上工作了一段时间,我已经到了我认为我的一些对象没有像我期望的那样被垃圾收集的地步。

我是如何做出这个决定的?

我在希望被垃圾回收的类中添加了带有断点的终结器。我运行我的应用程序并触发一系列事件,这些事件将 a)创建对象,然后 b)导致对象被谴责(理论上)。例如,我打开一个对话框然后关闭它等等。我的终结器没有被调用。

只是为了更加确定 GC 不会花费过长的时间,或者对象以某种方式被提升到老一代,因此没有以相同的速度被收集,我什至创建了一个定期强制垃圾收集的线程,即:

System.GC.Collect();
System.GC.WaitForPendingFinalizers();

仍然没有命中终结器断点。在这一点上,我相当确定有一些参考阻止了这些对象被收集,但我无法确定是什么。

所以我的问题有两个:

  1. 根据我的测试,我的结果是否有效?
  2. 如果是这样,是否有一些 我可以用来确定对象引用的机制或工具 (即对象引用链的可视化表示)?

提前致谢!

【问题讨论】:

  • 也许析构函数没有运行,因为不需要内存。垃圾收集器决定何时需要释放内存。
  • 您是否尝试过在 Visual Studio 中使用内存分析器?我认为它适用于您的项目类型。
  • 内存分析器向我显示分配和使用情况,但我需要找出谁持有对特定对象的引用。我可以看到探查器对于确定性能很有用,但我似乎无法获得我正在寻找的详细信息(我不否认我可能缺乏关于如何有效使用探查器工具的知识......)
  • 不要尝试在调试器中验证这一点 - 它可以延长对象的生命周期。运行 RElase 版本并使用日志记录。
  • 贴出相关代码(大纲)。到目前为止,您还没有证明这里有任何问题。

标签: c# garbage-collection


【解决方案1】:

这可能不是您问题的确切答案,因为我看不到您的代码 - 但我发现对我来说最常见的是,当一个对象没有被垃圾收集时,通常是因为我忘记取消订阅某处的事件。当您订阅一个事件时,您确实会创建一个引用,以防止您的课程被收集。

另一方面,垃圾收集器是一个非常不可预测的过程。我记得在某处读到,即使您致电 GC.Collect,也不能保证您的未引用类会立即被收集。

【讨论】:

  • 这是我所期望的,但对于我的一生,我找不到任何我没有取消订阅的事件订阅:(
【解决方案2】:

通过调用GC.CollectGC.WaitForPendingFinalizers,您可以确保终结器将启动,但您还需要确保此代码正在调用。断点it(或者更确切地说,WaitForPendingFinalizers 之后的方法关闭)以确保代码正在执行。

由于这是一个 WPF 项目,通过在您正在处理的任何视图中使用 PreviewKeyDown 来插入“调试按钮”也可能会有所帮助,该视图检查特定键,然后在否则为否时设置断点-操作if。将您的垃圾收集代码放在这里应该同样确保您的代码正在执行。

如前所述,事件处理程序也可以硬引用,因此请注意使用事件的任何地方,并意识到 WPF 与PropertyChanged 挂钩很多。

【讨论】:

  • 我已经做到了。所以我可以验证我正在强制执行 GC 过程,但我没有看到我的终结器受到攻击。所以我有信心在某处有参考。我想我现在想要找到的主要事情是如何判断谁持有参考资料
  • 嗯,您的 IDE 应该允许您搜索任何和所有对象的任何和所有引用。自从我自己使用 Visual Studio 已经有一段时间了,但我想它可以让你做到这一点。 MonoDevelop 可以。只需检查对您认为应该收集但不应该收集的任何对象的引用,看看您是否可以弄清楚是否有任何对象阻止了收集。基本上,这是一个淘汰的过程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多