资源必须用手清理了在C#?
-
02-07-2019 - |
题
什么样的资源必须用手清理了在 C# 和什么样的后果不这样做呢?
例如,说我有下列代码:
myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
// Use Brush
如果我不清刷使用的处置方法,我假设垃圾回收释放所使用的存储器在程序终止?这是正确的?
什么其他资源,我需要做手干净吗?
解决方案
从技术上讲,应该主动处理从IDisposable继承的任何内容。您可以使用'using'语句来简化操作。
http://msdn.microsoft.com/en-us/library /yh598w02.aspx
有时您会在文档示例代码中看到IDisposable派生对象的不一致使用以及由工具(即visual studio)生成的代码。
IDisposable的优点在于它使您能够主动发布基础非托管资源。有时您真的想要这样做 - 例如,考虑网络连接和文件资源。
其他提示
如果你没有处理某些东西,当垃圾收集器注意到你的代码中没有对它的引用时,它会被清理掉,这可能需要一段时间。对于类似的东西,它并不重要,但对于一个打开的文件,它可能会这样做。
一般情况下,如果某些东西有Dispose方法,你应该在完成后调用它,或者,如果可以的话,用语句将它包装在中:
using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
// use myBrush
}
- 处理内部窗户的数据结构。
- 数据库的连接。
- 文件处理。
- 网络连接。
- COM/OLE引用。
这样的例子不胜枚举。
重要的是要呼叫 Dispose
或甚至更好的是,使用 using
模式。
using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
// use myBrush
}
如果你不处理掉一些东西,它就会被清理干净的时候垃圾回收的通知的,有没有更多的提到它,这可能是后一些时间。
在这种情况下的 System.Drawing.Brush
, Windows将保持内部窗口的结构对于刷装在存储器,直到所有程序释放他们的处理。
不处理您的IDisposables的后果可能会从可忽略的性能影响到崩溃您的应用程序。
示例中的Brush对象将在GC感觉到它时被清理干净。但是你的程序不会受益于你早先清理它所获得的额外内存。如果您使用了大量的Brush对象,这可能会变得很重要。如果GC没有很长时间,那么GC也可以更有效地清理对象,因为它是一代分类垃圾收集器。
另一方面,不处理数据库连接对象的后果可能意味着您很快耗尽池化数据库连接并导致应用程序崩溃。
使用
using (new DisposableThing...
{
...
}
或者,如果您需要在对象的生命周期内保持对IDisposable的引用,请在对象上实现IDisposable并调用IDisposable的Dispose方法。
class MyClass : IDisposable
{
private IDisposable disposableThing;
public void DoStuffThatRequiresHavingAReferenceToDisposableThing() { ... }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
//etc... (see IDisposable on msdn)
}
通常,任何实现IDisposable的东西都会导致您暂停和研究您正在使用的资源。
GC仅在存在内存压力时才会发生,因此您无法预测何时发生。虽然卸载AppDomain肯定会触发它。
正如其他人所说,使用是你的朋友。 我写了此博客条目如何以相当简单的方式实现IDisposable,通过分解最重要的部分来减少错误。
当我不记得给定对象是否是一次性资源时,我使用的技巧是键入“.Dispose”。 (最多!)声明后让Intellisense检查我:
MemoryStream ms = new MemoryStream().Dispose
然后删除.Dispose并使用using()指令:
using(MemoryStream ms = new MemoryStream())
{
...
}
好吧,只要你使用资源的托管版本并且不自己调用windows API,你应该没问题。当你得到的是IntPtr时,只担心必须删除/销毁资源,因为“windows handle” (以及很多其他的东西)在.NET中是已知的,而不是对象。
顺便说一下,一旦离开当前上下文,资源(与任何其他.NET对象一样)将被标记为收集,因此如果在方法内创建Brush,则在退出时将标记它。
如果它被管理(即框架的一部分),您不需要担心它。如果它实现了IDisposable,只需使用块将其包装在中。
如果您想使用非托管资源,那么您需要阅读终结者并自行实施IDisposable。
此问题下有更多细节
首先在程序终止时,您可以假设过程本身将消除该过程使用的内存。
在.NET中使用dispose或析构函数时,必须明白GC调用dispose函数的时间是不确定的。这就是为什么建议使用use或明确调用dispose。
使用文件等资源时,必须释放内存对象(如信号量和.net以外的资源)。
例如,SolidBrush需要处理,因为它是一个GDI对象并且生活在.net世界之外。
垃圾收集器不仅在程序终止时释放,否则它不会真正有用(在任何体面/最近的操作系统上,当进程退出时,操作系统会自动清除所有内存)。
与C / C ++相比,C#的一大优势在于您不必关心释放已分配的对象(至少大部分时间);当运行时决定(各种策略何时/如何做)时,gc会这样做。
许多资源不是由gc:文件,与线程相关的资源(锁),网络连接等处理的......
需要注意的一点是看起来小到GC的对象但不是......例如,在SharePoint API中,就GC而言,SPWeb对象的占用空间很小,所以收集的优先级低,但它确实抓住了GC不知道的一堆内存(我认为在堆中)。如果您要预先处理一大堆这些问题,您将遇到一些有趣的内存问题,请记住使用或处置!
而不是将对象视为“持有”对象。需要释放的资源,最好根据一个对象来考虑改变某些东西(可能在计算机之外!),这将会比它更长,如果它没有被撤消或“清理”,可能会有害,但是只有对象可以清理。虽然这种改变通常采用池中某些具体对象的形式标记为“忙”,但其精确形式无关紧要。重要的是需要撤消更改,并且对象包含执行此操作所必需的信息。
垃圾收集器将处理任何托管资源。在您的示例中,当垃圾收集器决定时,刷子将被清除,这将在最后一次引用刷子不再有效后的某个时间发生。
有些事情需要手动清理,但这些是从非托管源检索的指针,例如DLL调用,但.NET Framework中的任何内容都不需要这种处理。