有什么方法可以解决C#中的内存泄漏问题

时间:2009-03-27 14:48:39

标签: c# .net memory-leaks garbage-collection

我正在学习C#。据我所知,您必须正确设置以使垃圾收集器实际删除所有内容。我正在寻找你多年来从智慧中学到的智慧。

我来自C ++背景,并且非常习惯代码气味和开发模式。我想知道C#中的代码气味是什么样的。给我建议!

删除内容的最佳方法是什么?

如何解决“内存泄漏”的问题?


编辑:我正在尝试开发一个“总是为内存管理做的事情”的打卡列表


非常感谢。

10 个答案:

答案 0 :(得分:18)

C#,.NET Framework使用托管内存,所有内容(但分配的​​非托管资源)都是垃圾回收。

可以安全地假设托管类型总是被垃圾收集。其中包括arraysclassesstructures。随意做int[] stuff = new int[32];并忘掉它。

如果在类中打开文件,数据库连接或任何其他非托管资源,请实现IDisposable接口,并在Dispose方法中取消分配非托管资源。

任何实现IDisposable的类都应该显式关闭,或者在(我认为很酷)使用块中使用;

using (StreamReader reader = new StreamReader("myfile.txt"))
{
   ... your code here
}

这里.NET将在{}范围之外处理读者。

答案 1 :(得分:11)

GC的第一件事是它是非确定性的;如果您希望及时清理资源,请实施IDisposable并使用using;它不会收集托管内存,但可以帮助很多非托管资源和转发链。

特别需要注意的事项:

  • 大量固定(对GC可以做的事情有很多限制)
  • 许多终结者(你通常不需要它们;减慢GC)
  • 静态事件 - 保持大量大型对象图活着的简便方法;-p
  • 在廉价的长寿命物体上的事件,可以看到应该清理的昂贵物体
  • “捕获变量”意外地保持图表活着

调查内存泄漏......“SOS”是最简单的路线之一;您可以使用SOS查找某个类型的所有实例,以及可以看到它的内容等。

答案 2 :(得分:3)

一般来说,你越少担心C#中的内存分配,你就越好。我会把它留给一个分析器告诉我什么时候我有收集问题。

您无法像在C ++中那样在C#中创建内存泄漏。垃圾收集器总是“有你的后背”。你可以做的是创建对象并保持对它们的引用,即使你从不使用它们。这是一个需要注意的代码味道。

除此之外:

  • 了解收集频率的概念(出于性能原因)
  • 不要持有超过您需要的对象的引用
  • 在完成IDisposable之后立即处置实现IDisposable的对象(使用using语法)
  • 正确实施IDisposable interface

答案 3 :(得分:3)

我能想到的内存泄漏的主要来源是:

  • 保持对不再需要的对象的引用(通常在某种集合中)所以在这里你需要记住,你添加到你所引用的集合中的所有东西都将保留在内存中。

  • 有循环引用,例如让代表在活动中注册。因此,即使您明确地不引用对象,也无法收集垃圾,因为其中一个方法已注册为具有事件的委托。在这些情况下,您需要记住在丢弃引用之前删除委托。

  • 与本机代码互操作并且无法释放它。即使您使用实现终结器的托管包装器,CLR也不会足够快地清理它们,因为它不了解内存占用。您应该使用using(IDisposable){}模式

答案 4 :(得分:1)

内存管理需要考虑的另一件事是,如果要实现任何Observer模式而不是正确处理引用。

例如: 对象A监视对象B. 如果从A到B的参考没有处置属性,则GC将被丢弃,GC将不会合意地处置该对象。因为仍然分配事件处理程序GC不会将其视为未使用的资源。

如果您正在使用一小组对象,这可能与我无关。但是,如果您使用数千个对象,这可能会导致应用程序生命周期内的内存逐渐增加。

有一些很棒的内存管理软件应用程序可以监视应用程序堆的内容。我发现使用.Net Memory Profiler可以带来很大的好处。

HTH

答案 5 :(得分:1)

我建议使用 .NET Memory Profiler

.NET Memory Profiler是一个功能强大的工具,用于查找内存泄漏并优化用C#,VB.NET或任何其他.NET语言编写的程序中的内存使用情况。

.NET Memory Profiler将帮助您:

  • 查看实时内存和资源信息
  • 通过收集和比较.NET内存的快照
  • 轻松识别内存泄漏
  • 查找未妥善处理的实例
  • 获取有关非托管资源使用情况的详细信息
  • 优化内存使用
  • 调查生产代码中的内存问题
  • 执行自动内存测试
  • 检索有关本机内存的信息

看看他们的视频教程:

http://memprofiler.com/tutorials/

答案 6 :(得分:1)

其他人已经提到了IDisposable的重要性,以及代码中需要注意的一些事项。

我想建议一些额外的资源;在了解.NET GC的详细信息以及如何解决.NET应用程序中的内存问题时,我发现以下内容非常宝贵。

杰弗里里希特的

CLR via C#是一本优秀的书。值得购买的价格只是关于GC和内存的章节。

blog(由Microsoft“ASP.NET升级工程师”)通常是我使用WinDbg,SOS以及发现某些类型的内存泄漏的提示和技巧的首选来源。 Tess甚至设计了.NET调试演示/实验室,它将引导您解决常见的内存问题以及如何识别和解决它们。

Debugging Tools for Windows(WinDbg,SOS等)

答案 7 :(得分:0)

  
    

删除内容的最佳方法是什么?

  

注意:以下内容仅适用于包含非托管资源的类型。它对纯托管类型没有帮助。

可能最好的方法是实现并遵循IDisposable模式;并在实现它的所有对象上调用dispose方法。

'使用'声明是你最好的朋友。松散地说,它会在实现IDisposable的对象上调用dispose。

答案 8 :(得分:0)

您可以使用像CLR profiler这样的工具,这需要一些时间来学习如何正确使用它,但毕竟它是免费的。 (它帮我找了几次内存泄漏)

答案 9 :(得分:0)

确保删除对象或在.NET术语中进行垃圾收集的最佳方法是确保所有根引用(可以通过方法和对象跟踪线程调用堆栈上第一个方法的引用)对象设置为null。

如果对象有任何有根引用,GC不能也不会收集对象,无论它是否实现了IDisposable。

循环引用没有惩罚或内存泄漏的可能性,因为GC标记它在对象图中访问了哪些对象。对于委托或事件处理程序,可能常常忘记将事件中的引用移除到目标方法,以便在事件被植根时无法收集包含目标方法的对象。