我正在学习C#。据我所知,您必须正确设置才能使垃圾回收器按照应该的方式删除所有内容。我想从您这里学到多年积累的智慧。
我来自C++背景,并非常习惯代码味道和开发模式。我想了解C#中的代码味道是什么样子的。给我一些建议!
最好的获取删除内容的方法是什么?
如何确定您是否存在"内存泄漏"?
编辑:我正在尝试制定“内存管理必须始终做的事情”清单
非常感谢。
我正在学习C#。据我所知,您必须正确设置才能使垃圾回收器按照应该的方式删除所有内容。我想从您这里学到多年积累的智慧。
我来自C++背景,并非常习惯代码味道和开发模式。我想了解C#中的代码味道是什么样子的。给我一些建议!
最好的获取删除内容的方法是什么?
如何确定您是否存在"内存泄漏"?
编辑:我正在尝试制定“内存管理必须始终做的事情”清单
非常感谢。
C#使用托管内存,除了已分配的非托管资源之外,所有东西都会被垃圾回收。可以安全地假设托管类型始终会被垃圾回收,包括数组、类和结构体。可以随意执行“int[] stuff = new int[32];”并将其忘记。
如果在类中打开文件、数据库连接或任何其他非托管资源,请实现IDisposable接口,并在Dispose方法中释放非托管资源。
任何实现IDisposable接口的类都应该显式关闭或在Using块中使用(我认为很酷)。
using (StreamReader reader = new StreamReader("myfile.txt"))
{
... your code here
}
在这里,.NET会在 { } 范围外释放读取器。
关于GC的第一件事是它是不确定性的;如果你想要资源快速清理,请实现IDisposable
并使用using
;这并不会清除托管内存,但可以在处理非托管资源和向前链时提供很大的帮助。
特别需要注意以下几点:
要调查内存泄漏,"SOS" 是最容易的路线之一;你可以使用 SOS 找到类型的所有实例以及能够访问它的内容等。
保留对不再需要的对象的引用(通常是在某种集合中)。因此,在向您拥有引用的集合中添加的所有内容都将保留在内存中。
存在循环引用,例如使用委托注册事件。即使您明确不引用对象,但由于其方法之一已注册为事件的委托,因此无法进行垃圾回收。在这些情况下,您需要记住在丢弃引用之前删除委托。
在考虑内存管理时,另一件需要考虑的事情是是否实现了任何观察者模式并且没有正确处理引用。
例如: 对象A监视对象B 如果从A到B的引用未通过属性释放,则对象B将被释放,GC将无法正确地处理该对象。因为事件处理程序仍然被分配,GC不会将其视为未使用的资源。
如果您正在处理少量对象,则可能与此无关。但是,如果您要处理数千个对象,则可能会导致应用程序的生命周期内逐渐增加内存。
有一些出色的内存管理软件应用程序可以监视应用程序堆中发生的情况。我发现使用.NET内存分析器非常有益。
希望对您有所帮助。
我建议使用.NET Memory Profiler
.NET Memory Profiler是一个强大的工具,用于查找内存泄漏并优化使用C#、VB.NET或任何其他.NET语言编写的程序的内存使用。
.NET Memory Profiler将帮助您:
请查看他们的视频教程:
其他人已经提到了IDisposable的重要性,以及在您的代码中需要注意的一些事项。
我想建议一些额外的资源;当学习.NET GC的详细信息以及如何解决.NET应用程序中的内存问题时,我发现以下资源非常宝贵。
CLR via C#由Jeffrey Richter撰写的书籍非常好。仅购买GC和内存章节就值得了。
这个博客(由微软“ASP.NET升级工程师”编写)通常是我寻找WinDbg、SOS的技巧和诀窍以及发现某些类型的内存泄漏的首选来源。Tess甚至设计了.NET调试演示/实验室,将引导您解决常见的内存问题并学会如何识别和解决它们。
Windows调试工具(WinDbg、SOS等)
确保对象被删除或在.NET术语中进行垃圾回收的最佳方法是确保对一个对象的所有根引用(可以通过方法和对象跟踪到线程调用堆栈上的第一个方法的引用)都设置为null。
如果有任何根引用指向一个对象,无论它是否实现IDisposable,GC都不能也不会收集该对象。
循环引用不会产生任何惩罚或可能导致内存泄漏,因为GC标记了它已经访问过的对象。在委托或事件处理程序的情况下,可能会忘记从事件中删除对目标方法的引用,因此如果事件被根引用,则包含目标方法的对象无法被收集。