如何找到处置和内存问题? C#

我的应用程序不久前使用的是150mb内存,现在是286mb。 它慢慢上升所以我必须忘记处理某些东西。 这对我来说不是一个问题,因为我有4gb,但我想把它发送给只有1gb内存的其他人。 然后逐行检查代码我怎样才能找到需要处理的对象或者只是一般大的对象?

延伸JP和Reed的答案。

我想澄清一点混乱。 如果您看到内存显着增加,则调用Dispose时不会出现问题。 Dispose通常用于释放非托管资源,如句柄。 这些不占用太多内存,而是作为资源更珍贵。

内存的增加通常与可从直接或间接通过堆栈对象或强GC句柄间接生根的托管对象访问的大对象或集合相关联。 这是您可能希望重点调查的领域。

查看.NET Memory Profiler 。 有一个为期15天的试用版,非常值得许可费。

通过收集和比较.NET内存快照轻松识别内存泄漏快照包括有关收集快照时.NET实例分配和实时实例的数据。 它们提供了大量有用的信息,可以轻松识别潜在的内存泄漏,尤其是在比较两个快照时。

您还可以使用WinDbg和SOS。 如果有点习惯,它们具有免费且非常彻底的优点。

这是一篇描述该过程的博客文章 。

代码项目目前有一个专门用于查找未处理对象的应用程序的链接。

http://www.codeproject.com/KB/dotnet/undisposed.aspx

看看这个链接

Stephen Toub竭尽全力解释这样做的各种技巧,以下是他的文章中的一些简短的亮点

  • 通过添加一个终结器用于调试目的,你可以介绍一种方法来找出何时没有正确处理类,如果从不调用终结器,你知道没有调用dispos

  • 为了获得有关实例,threadIds等的其他信息以帮助缩小哪个实例没有调用它,他创建了一个FinalizationDebgger类,你的一次性类将保留在该类上,当它调用FinalizationDebugger类实例的Dispose时本身被处置。 如果没有在类实例上调用Dispose,那么当Finalizer运行时,它将调用FinalizationDebgger实例的终结器,您可以在其中断言或抛出exception以帮助调试问题,

  • 将所有跟踪相关的代码移动到您的一次性类将inheritance的基类中,这使代码更清晰。 这种方法可能会也可能不会起作用,因为您已经烧了基类,并且已经从另一个基类inheritance。

  • 在最后一个选项中,所有内容都被分解为实例调用的静态类。 FinalizationDebugger成为一个静态类,它暴露了三个静态方法:Constructor,Dispose和Finalizer。 这个想法是你从类中的适当位置调用这些方法(dispose / finalize / constructor)。这对你的代码来说是微创的,因为它通常只涉及三行代码。 所有这些方法都使用ConditionalAttribute标记,这样只有在DEBUG模式下编译类时,它们才会被类调用。

斯蒂芬还解释了他的每一种方法的利弊。 解决方案提供了各种选项,您需要对每个选项进行评估,以确定哪种方案最适合您的情况。 必须阅读恕我直言

希望这可以帮助。

还可以试试ANTS Memory Profiler 。 这是一个为期14天的全function免费试用版,我非常喜欢用户界面。

披露:他们现在赞助Herding Code,这就是我试用它的原因。 但我对此印象非常深刻 – 我将应用程序描述了30个小时,并获得了大量有用的信息。 用户界面非常有用 – 它引导您完成整个过程,它看起来像是真的。

alt text http://sofzh.miximages.com/c%23/object_retention_graph.gif

以下是使用ANTS Memory Profiler帮助查找未处理对象并修复泄漏的几个技巧。

  1. ANTS内存分析器允许设置filter,仅显示包含Dispose()方法的对象。 打开它,您将获得一个尚未处置的活动对象列表。

  2. 虽然找到未曝光的对象是有用的,但更有用的是知道为什么不处理这些对象。 找到这些未曝光对象的创建位置对于找到泄漏原因还有很长的路要走。 如果您能够更改泄漏对象的代码,一个有用的技巧是引入一个字段来保存堆栈跟踪,并在对象构造时填充此字段。 然后,因为ANTS内存分析器允许您检查对象的字段,所以您可以简单地读取堆栈跟踪,就像创建泄漏对象时一样。 这将为您提供一个强有力的线索,告知泄漏对象的所有者应该是谁,以及他们应该如何在他们负责的对象上调用Dispose。