[英]What is the difference between the resources disposed in a finalizer to those released in dispose
这是这个问题的后续问题:
所以我明白,如果我正在创建一个使用非托管资源的类,我应该处理它们。 链接问题中的答案说终结器处理非托管资源。 但是, Dispose(Boolean)
方法也在处理非托管资源:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
那么终结器的处置和dispose方法的处置有什么区别呢?
您使用它的唯一原因(及其引起极大争议)。
Dispose()
方法,则可以释放非托管资源,从而避免泄漏。 不这样做的原因有很多,而错误的原因也有很多。 简而言之,很少有理由需要这样做或想要这样做
除了给出的答案:finalizer在运行时由垃圾收集器调用。
因此,您不能依赖于在终结器中释放非托管资源的时间! 因为它是未知的。
另外,终结器在另一个线程上运行,因此当垃圾回收完成时,终结器可能仍在运行! 因此必须通过另一个垃圾回收来完全摆脱对象。
因此,第一个垃圾回收会调用finalezrs,但是不会收集对象(还有对象所引用的对象),它将在第二个垃圾回收中收集。
具有终结器的对象经历GC的两个阶段:第一次运行终结器,第二次,实际上收集了对象并释放了内存。 除了增加GC压力并延迟将内存释放回池之外,终结器还具有处理其字段可能处于无效状态的对象的功能。 另外,在终结器线程上引发异常会立即破坏整个应用程序,而没有任何关于发生了什么的友好信息。
这就是为什么Dispose模式实现始终以对GC.SuppressFinalize
的调用为特征的原因,如果对象已被处置并且GC可以在第一次运行时直接释放内存,则该终结器将无法运行终结器。
通常,如果您的应用程序应能够承受严重异常(例如内存不足或线程异常中止以及随后的AppDomain卸载),则使用终结器可能会非常复杂和棘手。SQLServer或IIS等应用程序就是这种情况。
长话短说:除非绝对必要,否则不要使用终结器,并且如果必须(例如,使用非托管资源),则有很多研究在等待您。
您可以在以下博客文章中找到有关此主题的更多信息:
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()
方法和GC.SuppressFinalize(this);
具有Dispose(true)
GC.SuppressFinalize(this);
禁用~finalizer
调用,因为在清除对象成员之后没有必要,并且不必两次调用Dispose(bool disposing)
。
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.