[英]What are ways to solve Memory Leaks in C#
我正在学习C#。 据我所知,您必须正确设置以使垃圾收集器实际删除所有内容。 我正在寻找多年来从你那里学到的智慧,聪明。
我来自C ++背景,非常习惯代码气味和开发模式。 我想知道C#中的代码气味是什么样的。 给我建议!
删除内容的最佳方法是什么?
如何解决“内存泄漏”问题?
编辑:我正在尝试开发一个“总是为内存管理做的东西”的列表
非常感谢。
C#,.NET Framework使用托管内存,所有内容(但分配的非托管资源)都是垃圾回收。
可以安全地假设托管类型总是被垃圾收集。 这包括arrays
, classes
和structures
。 随意做int[] stuff = new int[32];
并忘掉它。
如果在类中打开文件,数据库连接或任何其他非托管资源,请实现IDisposable接口,并在Dispose方法中取消分配非托管资源。
任何实现IDisposable的类都应该显式关闭,或者在(我认为很酷)使用块中使用;
using (StreamReader reader = new StreamReader("myfile.txt"))
{
... your code here
}
这里.NET将在{}范围之外处置读取器。
GC的第一件事是它是非确定性的; 如果你想清理的资源及时,实现IDisposable
并使用using
; 这不会收集托管内存,但可以帮助很多非托管资源和转发链。
特别需要注意的事项:
为了调查内存泄漏......“SOS”是最简单的路线之一; 您可以使用SOS查找类型的所有实例,以及可以看到它的内容等。
一般来说,你越少担心C#中的内存分配,你就越好。 当我遇到收集问题时,我会把它留给分析师告诉我。
您不能像在C ++中那样在C#中创建内存泄漏。 垃圾收集器总是“有你的后背”。 你可以做的是创建对象并保持对它们的引用,即使你从不使用它们。 这是一个需要注意的代码味道。
除此之外:
using
语法) 我能想到的内存泄漏的主要来源是:
保持对你不再需要的对象的引用(通常在某种集合中)所以在这里你需要记住,你添加到你已经引用的集合中的所有东西都将保留在内存中。
有循环引用,例如让代表在事件中注册。 因此,即使您明确地不引用对象,也无法收集垃圾,因为其中一个方法已注册为具有事件的委托。 在这些情况下,您需要记住在丢弃引用之前删除委托。
内存管理需要考虑的另一个问题是,如果要实现任何Observer模式而不是正确处理引用。
例如:对象A监视对象B对象B如果从A到B的引用没有处置属性,则GC将被处置,GC将不会处置该对象。 因为仍然分配事件处理程序GC不会将其视为未使用的资源。
如果您正在使用一小组对象,这可能与我无关。 但是,如果您使用数千个对象,这可能会导致应用程序生命周期内的内存逐渐增加。
有一些很棒的内存管理软件应用程序可以监视应用程序堆的内容。 我发现使用.Net Memory Profiler可以带来很大的好处。
HTH
我建议使用.NET Memory Profiler
.NET Memory Profiler是一个功能强大的工具,用于查找内存泄漏并优化用C#,VB.NET或任何其他.NET语言编写的程序中的内存使用情况。
.NET Memory Profiler将帮助您:
看看他们的视频教程:
其他人已经提到了IDisposable的重要性,以及您的代码中需要注意的一些事项。
我想建议一些额外的资源; 在了解.NET GC的详细信息以及如何解决.NET应用程序中的内存问题时,我发现以下内容非常宝贵。
CLR通过C# by Jeffrey Richter是一本很好的书。 值得购买的价格只是关于GC和内存的章节。
此博客 (由Microsoft“ASP.NET升级工程师”)通常是我使用WinDbg,SOS以及发现某些类型的内存泄漏的提示和技巧的首选来源。 Tess甚至设计了.NET调试演示/实验室,它将引导您解决常见的内存问题以及如何识别和解决它们。
适用于Windows的调试工具 (WinDbg,SOS等)
删除内容的最佳方法是什么?
注意:以下内容仅适用于包含非托管资源的类型。 它对纯托管类型没有帮助。
可能最好的方法是实现并遵循IDisposable模式; 并在实现它的所有对象上调用dispose方法。
'使用'声明是你最好的朋友。 松散地说,它会在实现IDisposable的对象上调用dispose。
您可以使用像CLR profiler这样的工具,它需要一些时间来学习如何正确使用它,但毕竟它是免费的。 (它帮我几次找到我的内存泄漏)
确保对象被删除或在.NET术语中进行垃圾收集的最佳方法是确保所有根引用(可以通过方法和对象跟踪线程调用堆栈上的第一个方法的引用)到对象设置为null。
如果对象有任何有根引用,GC无论也不会收集对象,无论它是否实现IDisposable。
循环引用没有惩罚或内存泄漏的可能性,因为GC标记它在对象图中访问了哪些对象。 在委托或事件处理程序的情况下,可能常常忘记将事件中的引用移除到目标方法,以便在事件被植根时无法收集包含目标方法的对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.