C# 获取对象的活动引用

C# 获取对象的活动引用,c#,.net,garbage-collection,C#,.net,Garbage Collection,我正在寻找一个托管/非托管API,它可以让我找到哪些对象引用了另一个对象,并有可能阻止它被垃圾收集 这样的API可能如下所示: var foo = new Foo(); var bar = new Bar(); bar.Foo = foo; var references = GC.GetReferencesTo(foo); // references is an array that contains bar 我知道分析器可以用于此,但我想将其作为单元测试的一部分。我是否可以使用托管或非托管

我正在寻找一个托管/非托管API,它可以让我找到哪些对象引用了另一个对象,并有可能阻止它被垃圾收集

这样的API可能如下所示:

var foo = new Foo();
var bar = new Bar();
bar.Foo = foo;

var references = GC.GetReferencesTo(foo);
// references is an array that contains bar
我知道分析器可以用于此,但我想将其作为单元测试的一部分。我是否可以使用托管或非托管API

非托管dll SOS(Strike之子)提供了一种实现这一点的方法,尽管我认为它没有显著的脚本支持,也没有提供通过单个命令实现这一点的简单方法。您必须内省变量的地址,检查变量的所有gcroots(显然包括堆栈),并处理剩余部分

我建议,如果你想证明一个对象没有被引用,一个更简单的方法是(暂时)使它可以被终结,确保它不再被单元测试的堆栈引用,然后通过then use强制进行几个垃圾收集

finalize方法可以设置一个静态布尔标志,然后单元测试可以断言这是真的

我会质疑这一点的实用性,不作进一步解释,但这可能是证明单元测试中不存在悬空引用的最简单方法。

还请记住.NET使用其他对象引用的对象(例如对象图),如果您的应用程序没有引用任何对象,GC仍会清理这些对象比较长的它比.NET之前的经典引用计数垃圾收集算法聪明得多。这意味着,即使您找到了一种方法来精确定位对对象的所有引用,其中一些可能并不重要,也可能不需要注意

这并不能直接回答如何找到一个对象的所有引用,但会让读者意识到这样一种情况:当你们通过一个工具或实用工具找到所有引用时,有些东西不再需要在.NET中修复,例如经典的循环引用,因此,在试图修复内存泄漏时,您可能需要寻找一些巧妙的方法来知道应该忽略什么

此解释仅适用于托管代码场景

.NET探查器使用跟踪对象的图形。您可能对回调方法
ObjectReferences
RootReferences
特别感兴趣,还可能对
ObjectAllocated
感兴趣。在每次垃圾收集之后,将调用前两个方法来覆盖整个活动对象图,因此仅拦截它们就足以重建该图,然后以任何方式对其进行分析


解释如何将所有部分放在一起。

我当前使用对对象的WeakReference,后跟GC.Collect/WFPF,然后断言引用为null,以告诉我是否已清除。我这样做是作为单元测试的一部分,以确保我的API不会导致泄漏。但是,作为“断言”输出的一部分,我想打印出哪些对象使其保持活动状态,以避免我跳入探查器。我严重怀疑,如果不亲自公开SOS功能,而不进行大量工作,这是否可能以自动方式实现,除非MS内部已经有人这样做了。我建议最好的方法是基于SOS编写一些东西,将整个搜索自动化到一个命令中,这样您就可以从调试器中的失败测试中触发它。请注意,SOS不是一个独立的工具,它完全依赖于所连接的兼容调试器……如果您真的想尝试破解它,这里有一个出发点:还可以看看一些人在包装SOS时使用了什么工具:请参阅此相关问题:该链接缺少文章