调试.NET内存泄漏 - 如何知道什么是抱着什么参考?(Debugging .NET memory

2019-06-25 16:03发布

我工作的地方似乎有内存泄漏.NET应用程序。 我知道教科书的答案,即事件应该被退订,一次性物品应置于等..

我有一个测试工具,可以重现错误。 在某一类的终结我写的安慰

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

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

在测试工具,我创建美孚(这反过来又创造并与数百其他类型的相互作用)的单个实例,然后取出并调用垃圾收集器。

我发现了富终结永远不会被调用。 我有这种设置被敲定为控制测试类似的类。

所以我的问题是这样的:

如何确定使用的商业或开源工具到底是什么抱着foo的引用?

我公司有专业执照dotTrace存储器剖析,但不能从帮助文件如何使用它搞清楚。

更新:我现在用dotMemory 4.0 ,这是后继者(好,但不可用)dotTrace内存3.5。

Answer 1:

终结不确定性调用,所以用它来跟踪一个可靠的方式事情要小心处理。 如果删除终结,而是使用WeakReference<Foo>你应该能够确定对象是否被收集。

所有内存分析器应该能够找到一个问题像这样的,但不同的难度。 我曾亲自使用蚂蚁,这是非常容易的哟使用,但不是免费的。 它会帮助你展示的参考图的富实例,从GC根对象的所有道路。 见此图它通常是容易被发现是谁在持有的参考。



Answer 2:

调试内存泄漏可以说是相当复杂的过程,需要你的程序逻辑的透彻理解和至少一些净内部(尤其是垃圾收集器的行为)。

欲了解更多信息,请参阅以下链接:

好介绍

  • http://msdn.microsoft.com/en-us/library/ee658248.aspx

动手课程:

  • http://www.dotnetfunda.com/articles/article508.aspx
  • http://www.dotnetfunda.com/articles/article524.aspx

GC和.Net内部

  • http://blogs.msdn.com/b/tess/archive/2008/04/17/how-does-the-gc-work-and-what-are-the-sizes-of-the-different-generations。 ASPX
  • http://msdn.microsoft.com/en-us/magazine/cc163491.aspx
  • http://blogs.msdn.com/b/maoni/archive/2004/06/03/148029.aspx

WinDbg中与SOS扩展

  • http://www.codeproject.com/Articles/19490/Memory-Leak-Detection-in-NET
  • http://www.simple-talk.com/dotnet/.net-framework/investigating-.net-memory-management-and-garbage-collection/

祝好运!



Answer 3:

有一个看在SOS调试扩展(这是免费的,一个可以在Visual Studio中使用)。

您可能会发现这和这有助于获得startet。

如果你已经succefully设置了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


Answer 4:

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

MemProfiler

蚂蚁探查



Answer 5:

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

完成操作具有以下限制:

  • 当垃圾回收过程中执行终结的准确时间是不确定的。 资源不能保证在任何特定的时间释放,除非调用Close方法或Dispose方法。

  • 两个对象的终结不能保证在任何特定的顺序运行,即使一个对象指的是其他。 也就是说,如果对象A有一个参考对象B并且都终结,对象B可能已经对象A的终结开始时敲定。

  • 在其上运行的终结线程是不确定的。

引用自: http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx
我会建议使用Dispose方法来代替。

其次,任何内存分析器应该能够查找并持有这些引用。 我个人是用蚂蚁探查,这是一个非常好的工具,具有相当丰富的文档。 你可以试着读这篇文档: http://downloads.red-gate.com/HelpPDF/ANTS_Memory_Profiler/InstanceCategorizer.pdf从对象集合到GC根引用的实例分类显示链。



文章来源: Debugging .NET memory leaks - how to know what is holding a reference to what?