我正在寻找一个托管/非托管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吗?
答案 0 :(得分:5)
非托管dll SOS(Son Of Strike)提供了实现这一目标的方法,虽然我不相信它具有重要的脚本支持,也没有提供通过单个命令实现此目的的简单方法。您必须反省变量的地址,检查变量的所有gcroots(显然包括堆栈)并处理余数。
我建议,如果你想证明一个对象不被引用,一个更简单的技术是(暂时)使它可以完成,确保它不再被引用到堆栈上您的单元测试,然后通过GC.Collect()强制执行几个垃圾收集,然后使用GC.WaitForPendingFinalizers()。
你的finalize方法可以设置一个静态布尔标志,然后你的单元测试可以断言这是真的。
我会在没有进一步解释的情况下质疑实用程序,但这可能是证明单元测试中没有悬空引用的最简单方法。
答案 1 :(得分:3)
.NET Profiler使用profiling API来跟踪对象图。您可能对回调方法ObjectReferences
和RootReferences
以及ObjectAllocated
特别感兴趣。在每次垃圾收集之后,将调用前两个方法来覆盖整个活动对象图,因此单独拦截它们就足以重建该图,然后以您想要的任何方式对其进行分析。
This article解释了如何将所有部分放在一起。
答案 2 :(得分:1)
还记得.NET使用traced garbage collection所以其他对象引用的对象 - 例如对象图 - 如果您的应用不再引用其中任何一个,GC仍将清理它们;它比.NET之前的经典引用计数垃圾收集算法更加智能。这意味着即使您找到一种方法来精确定位对象的所有引用,其中一些可能无关紧要,可能不需要处理。
这并没有直接回答如何找到对象的所有引用,但确实让读者意识到当你通过工具或实用程序找到所有引用时,某些事情不需要在.NET中被修复 - 例如经典的循环引用,因此您可能需要寻找一些巧妙的方法来了解在尝试修复内存泄漏时要忽略的内容。
此说明仅适用于托管代码方案。