我正在开发一个似乎存在内存泄漏的.NET应用程序。我知道教科书的答案,事件应该取消订阅,一次性物品应该处理等......
我有一个可以重现错误的测试工具。在某个类的终结器中,我写入控制台
public class Foo
{
// Ctor
public Foo()
{
}
~public Foo()
{
Console.WriteLine("Foo Finalized");
}
}
在测试工具中,我创建了一个Foo实例(反过来创建并与数百种其他类型交互)然后删除它并调用垃圾收集器。
我发现永远不会调用Foo Finalizer。我有一个类似的类与此设置,最终确定为控制测试。
所以我的问题是:
如何确定使用商业或开源工具 拿着对Foo的引用?
我拥有dotTrace内存分析器的专业许可,但无法从帮助文件中找出如何使用它。
更新:我现在正在使用dotMemory 4.0,它是(好的,但无法使用的)dotTrace Memory 3.5的继承者。
答案 0 :(得分:6)
look扩展名为SOS debugger(免费提供,可在Visual Studio中使用)。
如果你成功设置了SOS(有时候这可能很棘手),知道什么是什么就像
那样容易// load sos
.load sos
// list of all instances of YourTypeName in memory with their method tables
!DumpHeap -type YourTypeName
// put here the method table displayed by the previous command
// it will show you the memory address of the object
!DumpHeap -mt 07f66b44
// displays information about references the object at the specified address
!GCRoot 02d6ec94
答案 1 :(得分:6)
调试内存泄漏可能是一个非常复杂的过程,需要彻底了解您的程序逻辑和至少一些.Net内部(尤其是垃圾收集器行为)。
有关详细信息,请参阅以下链接:
好的介绍
实践课程
GC和.Net内部
带有SOS扩展名的WinDbg
祝你好运!
答案 2 :(得分:3)
终结器未被确定性地调用,因此请注意使用它以可靠的方式跟踪事物。如果删除终结器而使用WeakReference<Foo>
,则应该能够确定是否收集了对象。
所有内存分析器都应该能够找到这样的问题,但具有不同程度的难度。我个人使用的ANTS非常容易使用,但不是免费的。它将帮助您从GC根对象一直显示Foo实例的参考图。看到这个图表,通常很容易发现谁持有参考。
答案 3 :(得分:2)
答案 4 :(得分:1)
首先你不应该使用终结器,因为:
Finalize操作具有以下限制:
在垃圾回收期间终结器执行的确切时间 未定义。资源不保证在任何时候发布 特定时间,除非调用Close方法或Dispose方法。
两个对象的终结器不能保证在任何对象中运行 特定顺序,即使一个对象引用另一个对象。也就是说,如果 对象A具有对象B的引用,并且都具有终结符Object 当对象A的终结器开始时,B可能已经完成。
未指定运行终结器的线程。
引自:http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx
我建议改用Dispose方法。
其次,任何内存分析器都应该能够找到保存这些引用的内容。我个人使用的是ANTS Profiler,它是一个非常好的工具,并且有相当丰富的文档。您可以尝试阅读此文档:http://downloads.red-gate.com/HelpPDF/ANTS_Memory_Profiler/InstanceCategorizer.pdf 实例分类程序显示从对象集到GC根目录的引用链。