问题描述
如果我理解正确,.net 运行时将始终在我之后清理.因此,如果我创建新对象并停止在代码中引用它们,运行时将清理这些对象并释放它们占用的内存.
If I understand correctly the .net runtime will always clean up after me. So if I create new objects and I stop referencing them in my code, the runtime will clean up those objects and free the memory they occupied.
既然是这种情况,为什么有些对象需要有析构函数或处置方法呢?当它们不再被引用时,运行时不会在它们之后清理吗?
Since this is the case why then do some objects need to have a destructor or dispose method? Won’t the runtime clean up after them when they are not referenced anymore?
推荐答案
需要终结器来保证将稀缺资源释放回系统,如文件句柄、套接字、内核对象等.由于终结器总是在最后运行在对象生命中,它是释放这些句柄的指定位置.
Finalizers are needed to guarantee the release of scarce resources back into the system like file handles, sockets, kernel objects, etc. Since the finalizer always runs at the end of the objects life, it’s the designated place to release those handles.
Dispose
模式用于提供资源的确定性销毁.由于 .net 运行时垃圾收集器是非确定性的(这意味着您永远无法确定运行时何时会收集旧对象并调用它们的终结器),因此需要一种方法来确保系统资源的确定性释放.因此,当您正确实现 Dispose
模式时,您提供了资源的确定性释放,并且在消费者粗心且不释放对象的情况下,终结器将清理对象.
The Dispose
pattern is used to provide deterministic destruction of resources. Since the .net runtime garbage collector is non-deterministic (which means you can never be sure when the runtime will collect old objects and call their finalizer), a method was needed to ensure the deterministic release of system resources. Therefore, when you implement the Dispose
pattern properly you provide deterministic release of the resources and in cases where the consumer is careless and does not dispose the object, the finalizer will clean up the object.
为什么需要 Dispose
的一个简单示例可能是快速而肮脏的日志方法:
A simple example of why Dispose
is needed might be a quick and dirty log method:
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
对象上的终结器.这带来了一个问题,因为在此期间,可能会再次调用该方法来写入日志,但这一次它将失败,因为文件仍处于锁定状态.
In the above example, the file will remain locked until the garbage collector calls the finalizer on the StreamWriter
object. This presents a problem since, in the meantime, the method might be called again to write a log, but this time it will fail because the file is still locked.
正确的方法是在使用完对象后处理它:
The correct way is to dispose the object when are done using it:
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# 析构函数称为终结器",否则它们往往会将人们与 C++ 析构函数混淆,而 C++ 析构函数与 C# 不同,是确定性的.
BTW, technically finalizers and destructors mean the same thing; I do prefer to call c# destructors 'finalizers' since otherwise they tend to confuse people with C++ destructors, which unlike C#, are deterministic.
这篇关于既然 .NET 有一个垃圾收集器,为什么我们需要终结器/析构器/dispose-pattern?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!