8

我正在开发一个似乎存在内存泄漏的 .NET 应用程序。我知道教科书上的答案,应该取消订阅事件,应该处置一次性物品等......

我有一个可以重现错误的测试工具。在某个类的终结器中,我写信给控制台

public class Foo
{
   // Ctor
   public Foo()
   {
   }

   ~public Foo()
   {
       Console.WriteLine("Foo Finalized");
   }
}

在测试工具中,我创建了 Foo 的单个实例(它反过来创建并与数百种其他类型交互)然后删除它并调用垃圾收集器。

我发现永远不会调用 Foo 终结器。我有一个与此设置类似的课程,最终确定为控制测试。

所以我的问题是:

我如何使用商业或开源工具来确定究竟什么是对 Foo 的引用?

我有 dotTrace Memory profiler 的专业许可证,但无法从帮助文件中弄清楚如何使用它。

更新:我现在正在使用dotMemory 4.0,它是(好的,但不可用的)dotTrace Memory 3.5 的继承者。

4

5 回答 5

6

查看SOS调试器扩展(它是免费的,可以在 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
于 2012-06-21T08:15:41.373 回答
3

终结器不是确定性地调用的,所以要小心使用它以可靠的方式跟踪事物。如果您删除终结器并改为使用 aWeakReference<Foo>您应该能够确定对象是否被收集。

所有内存分析器都应该能够找到这样的问题,但难度不同。我个人使用过 ANTS,它很容易使用,但不是免费的。它将帮助您显示 Foo 实例的引用图,从 GC 根对象开始。看到这张图,通常很容易发现谁在持有参考。

于 2012-06-21T07:59:58.527 回答
2

您可以使用内存分析器来识别内存泄漏。这里有一些,

内存分析器

蚂蚁探查器

于 2012-06-21T07:55:11.937 回答
1

首先你不应该使用终结器,因为:

Finalize 操作具有以下限制:

  • 垃圾回收期间终结器执行的确切时间未定义。除非调用 Close 方法或 Dispose 方法,否则不保证在任何特定时间释放资源。

  • 不保证两个对象的终结器以任何特定顺序运行,即使一个对象引用另一个对象。也就是说,如果对象 A 具有对对象 B 的引用并且都具有终结器,则对象 B 可能在对象 A 的终结器启动时已经终结。

  • 运行终结器的线程未指定。

引用自: 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 根的引用链。

于 2012-06-21T08:17:03.703 回答