如果我理解正确,.net运行时将始终在我之后清理。因此,如果我创建新对象并且停止在代码中引用它们,则运行时将清理这些对象并释放它们占用的内存。
既然是这种情况,那么为什么某些对象需要具有析构函数或dispose方法?当不再引用它们时,运行时是否会清理它们?
Answers:
需要终结器来确保将稀缺资源(如文件句柄,套接字,内核对象等)释放回系统中。由于终结器始终在对象寿命结束时运行,因此它是释放这些句柄的指定位置。
该Dispose
模式用于提供确定性的资源破坏。由于.net运行时垃圾回收器是不确定的(这意味着您永远无法确定运行时何时收集旧对象并调用其终结器),因此需要一种方法来确保确定性释放系统资源。因此,当Dispose
正确实现模式时,您将提供确定的资源释放,并且在使用者不小心且不处置对象的情况下,终结器将清理该对象。
一个简单的示例说明为什么Dispose
需要这样做,这可能是一种快速而肮脏的日志方法:
public void Log(string line)
{
var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None));
sw.WriteLine(line);
// Since we don't close the stream the FileStream finalizer will do that for
// us but we don't know when that will be and until then the file is locked.
}
在上面的示例中,文件将保持锁定状态,直到垃圾回收器在StreamWriter
对象上调用终结器为止。这就带来了一个问题,因为与此同时,可能再次调用该方法以写入日志,但是这次它将失败,因为文件仍处于锁定状态。
正确的方法是在完成使用对象后处置它:
public void Log(string line)
{
using (var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) {
sw.WriteLine(line);
}
// Since we use the using block (which conveniently calls Dispose() for us)
// the file well be closed at this point.
}
顺便说一句,在技术上,终结器和析构函数的含义相同。我确实更喜欢将c#析构函数称为“ finalizers”,因为否则它们会使人与C ++析构函数相混淆,而C ++析构函数是确定性的。
先前的答案很好,但让我再次在这里强调重点。特别是你说
如果我理解正确,.net运行时将始终在我之后清理。
这只是部分正确。实际上,.NET仅提供对一种特定资源(主内存)的自动管理。所有其他资源都需要手动清理。1)
奇怪的是,在几乎所有有关程序资源的讨论中,主内存都具有特殊的地位。当然,这有一个很好的理由–主内存通常是最稀缺的资源。但值得记住的是,还有其他类型的资源也需要管理。
1)通常尝试的解决方案是将其他资源的生存期与代码中的内存位置或标识符的生存期耦合在一起,因此存在终结器。
using
具有优缺点,但我不确定前者是否胜过后者。当然,这取决于应用程序,但是在我编写的几乎每个程序中,非托管资源管理都是至关重要的部分,C ++在这里使我的生活变得更加轻松。
仅当系统没有内存压力时,垃圾收集器才会运行,除非它确实需要释放一些内存。这意味着,您永远无法确定GC何时运行。
现在,假设您是数据库连接。如果您在之后清理GC,则连接到数据库的时间可能会超出所需的时间,从而导致奇怪的负载情况。在这种情况下,您希望实现IDisposable,以便用户可以调用Dispose()或使用using()来确保连接尽快关闭,而不必依赖GC,后者可能会在以后运行。
通常,IDisposable可在任何使用非托管资源的类上实现。
真正的原因是因为.net垃圾收集并非旨在收集非托管资源,因此清除这些资源仍由开发人员负责。同样,当对象超出范围时,不会自动调用对象终结器。GC会在不确定的时间调用它们。当它们被调用时,GC不会立即运行它,而是等待下一轮调用它,从而增加了清理时间,这在对象持有稀缺的非托管资源(例如文件)时不是一件好事。或网络连接)。输入一次性模式,开发人员可在该模式下在确定的时间手动释放稀缺资源(调用yourobject.Dispose()或using(...)语句时)。请记住,您应该调用GC.SuppressFinalize(this); 在您的dispose方法中告诉GC该对象是手动处理的,不应最终确定。我建议您看看K. Cwalina和B. Abrams撰写的《框架设计指南》一书。它很好地说明了Disposable模式。
祝好运!
简单的解释:
实施Finalize方法的一些准则:
有关实现Dispose方法的一些准则:
需要描述符和处理方法的对象正在使用非托管资源。因此,垃圾收集器无法清理这些资源,因此您必须自己执行此操作。
查看IDisposable的MSDN文档。http://msdn.microsoft.com/zh-CN/library/system.idisposable.aspx
该示例使用非托管处理程序-IntPr。