这是该问题的后续问题:
Finalize/Dispose pattern in C#
所以我知道,如果我要创建一个使用非托管资源的类,则应该将其处置。链接问题中的答案表示终结器处理了非托管资源。但是,Dispose(Boolean)
方法也可以处理非托管资源:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
那么,终结器的处置与dispose方法的处置有什么区别?
答案 0 :(得分:3)
您会使用它的唯一原因(及其极具争议性)。
Dispose()
方法,则可以释放非托管资源,因此避免了泄漏。有很多理由不这样做,而且有很多方法可以弄错它。简而言之,很少有您需要这样做或想要这样做的原因
答案 1 :(得分:1)
除了给出的答案:终结器在运行时由垃圾收集器调用。
因此,您不能依赖在finalizer中释放不受管资源的时间!因为不知道。
另外,终结器在另一个线程上运行,因此当垃圾回收完成时,终结器可能仍在运行!因此必须通过另一个垃圾回收来完全摆脱对象。
因此,第一个垃圾回收会调用finalezrs,但是不会收集对象(还有对象所引用的对象),它将在第二个垃圾回收中收集。
答案 2 :(得分:0)
带有终结器的对象经历GC的两个阶段:第一次运行终结器,第二次,实际上收集了对象并释放了内存。除了增加GC压力并延迟将内存释放回池之外,终结器还具有处理其字段可能处于无效状态的对象的功能。另外,在终结器线程上引发异常会立即破坏整个应用程序,而没有任何关于发生了什么的友好信息。
这就是为什么Dispose模式实现始终以对GC.SuppressFinalize
的调用为特征的原因,这会导致终结器在对象已被处置且GC可以在第一次运行时直接释放内存的情况下不运行。
通常,如果您的应用程序应能够承受严重异常(例如内存不足或线程中止以及随后的AppDomain卸载),则使用终结器可能会非常复杂和棘手。SQLp或IIS等应用程序就是这种情况。
长话短说:除非绝对必要,否则不要使用终结器,并且如果必须这样做(例如,使用非托管资源),则有很多研究在等待着您。
您可以在以下博客文章中找到有关此主题的更多阅读内容:
答案 3 :(得分:0)
GC
在对象被收集之前的调用~finalizer
。
这意味着对象的托管成员也将被收集或已经收集(我不知道GC如何工作的细微差别)。
因此,不必清理托管成员,通常在Dispose(false)
中有~finalizer
来阻止它。
~B()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
当我们通过调用Dispose()
方法或使用using
手动处置对象时,应清理对象的成员并准备进行收集(将值设置为null等)。
因此,我们在Dispose(true)
方法中使用了Dispose()
,并且GC.SuppressFinalize(this);
禁用了~finalizer
调用,因为在对象成员已经清除之后不必调用Dispose(bool disposing)
,这是没有必要的两次。
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}