作者热门文章
- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
如果我理解正确,.net 运行时将始终在我之后清理。因此,如果我创建新对象并停止在代码中引用它们,运行时将清理这些对象并释放它们占用的内存。
既然是这种情况,为什么有些对象需要有析构函数或处置方法呢?当它们不再被引用时,运行时不会在它们之后清理吗?
最佳答案
需要终结器来保证将稀缺资源释放回系统,如文件句柄、套接字、内核对象等。由于终结器总是在对象生命周期结束时运行,因此它是释放这些句柄的指定位置。
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# 析构函数称为“终结器”,否则它们往往会将人们与 C++ 析构函数混淆,而 C++ 析构函数与 C# 不同,是确定性的。
关于c# - 既然 .NET 有一个垃圾收集器,为什么我们需要终结器/析构器/dispose-pattern?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/331786/
我是一名优秀的程序员,十分优秀!