由于.NET拥有垃圾收集器,为什么我们还需要finalizers/destructors/dispose-pattern呢?
由于.NET拥有垃圾收集器,为什么我们还需要finalizers/destructors/dispose-pattern呢?
如果我理解正确,.net运行时将始终为我进行垃圾回收。因此,如果我创建新的对象并且在代码中停止引用它们,运行时将清理这些对象并释放它们占用的内存。
既然如此,为什么一些对象需要有析构函数或dispose方法?当它们不再被引用时,运行时不会为它们进行清理吗?
admin 更改状态以发布 2023年5月22日
Finalizers(终结器)的作用是确保将稀缺资源(如文件句柄、套接字、核心对象等)释放回系统。由于终结器总是在对象生命结束时运行,因此它是释放这些句柄的指定位置。
使用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. }
顺便说一下,严格来说,finalizers和destructors意思相同;我喜欢称呼C#析构函数为“finalizers”,因为否则它们往往会与C++的析构函数混淆,后者与C#不同,具有确定性。