2009-11-24 52 views
4

我正在寻找托管/非托管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?

+1

看到这个相关的问题:http://stackoverflow.com/questions/1786083/how-do-i-iterate-through-instances-of-a-class-in-c/1786354#1786354 – 2009-11-24 00:29:55

回答

5

非托管dll SOS(Son of Strike)提供了一种实现此目的的方法,虽然我不相信它具有明显的脚本支持,也没有提供通过单个命令实现此目的的简单方法。你将不得不反思变量的地址,检查变量的所有gcroots(显然会包括堆栈)并处理其余部分。我会建议,如果你想证明一个对象是而不是引用,一个更简单的技术将(暂时)使其可以finalizeable,确保它不再引用你的单元测试堆栈和然后通过GC.Collect()强制多个垃圾收集,然后使用GC.WaitForPendingFinalizers()

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

我会质疑实用程序没有进一步的解释,但这可能是证明在单元测试中不存在悬挂参考的最简单方法。

+0

我目前使用WeakReference对象后面跟着一个GC.Collect/WFPF,然后声明引用为空来告诉我它是否已被清除。我将其作为单元测试的一部分来确保我的API不会导致泄漏。但作为'assert'输出的一部分,我想打印出哪些对象保持活动状态,以便让我跳进剖析器。 – 2009-11-24 00:23:30

+0

我认真地怀疑,如果没有大量的工作来自动公开SOS功能,那么这是可能的自动方式,除非MS内的人已经这样做了。我建议最好的办法是考虑编写基于SOS的东西,将整个搜索自动化到一个命令中,以便在调试器中从失败的测试中触发它。请注意,SOS不是一个独立的工具,它完全依赖于一个兼容的调试器被连接... – ShuggyCoUk 2009-11-24 00:44:14

+1

如果你真的想尝试破解它在这里的一个凝视点:http://blogs.microsoft.co.il/ blogs/sasha/archive/2009/08/17/gc-helper-for-obtain-live-instances-of-a-type-or-how-i-implemented-gc-getaliveinstancesof-lt-t-gt.aspx – ShuggyCoUk 2009-11-24 00:47:43

1

还记得.NET使用traced garbage collection所以其他对象引用的对象 - 例如对象图 - 如果您的应用程序不再引用任何对象,GC仍会清除它;它比经典的引用计数垃圾收集算法pre-.NET更聪明。这意味着,即使您找到一种方法来查明对象的所有引用,其中一些引用可能并不重要,也可能不需要照顾。

这并不直接回答如何找到一个对象的所有引用,但确实让读者了解的情况是,当你发现通过工具或实用程序的所有引用,某些种类的事情不需要在.NET中被修复 - 例如经典的循环引用,因此在尝试修复内存泄漏时,您可能不得不寻找一些巧妙的方法来知道要忽略什么。

此解释仅适用于托管代码方案。

3

.NET探查使用profiling API跟踪对象的曲线图。你可能特别感兴趣的回调方法ObjectReferencesRootReferences,也可能是ObjectAllocated。前两种方法将在每次垃圾回收后被调用来覆盖整个活动对象图,因此单独拦截它们就足以重建该图,然后以任何您想要的方式对其进行分析。

This article介绍了如何把所有的拼在一起。

+2

文章从该链接丢失 – TankorSmash 2015-11-13 01:32:51