繁体   English   中英

在终结器中处理的资源与在处理中释放的资源有什么区别

[英]What is the difference between the resources disposed in a finalizer to those released in dispose

这是这个问题的后续问题:

在 C# 中完成/处置模式

所以我明白,如果我正在创建一个使用非托管资源的类,我应该处理它们。 链接问题中的答案说终结器处理非托管资源。 但是, Dispose(Boolean)方法也在处理非托管资源:

protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    } 

那么终结器的处置和dispose方法的处置有什么区别呢?

您使用它的唯一原因(及其引起极大争议)。

  1. 终结器允许清除对象,然后再由垃圾回收器将其删除。 (也就是说,GC负责调用它,并从内存中清除对象)如果开发人员忘记调用对象的Dispose()方法,则可以释放非托管资源,从而避免泄漏。

不这样做的原因有很多,而错误的原因也有很多。 简而言之,很少有理由需要这样做或想要这样做

除了给出的答案:finalizer在运行时由垃圾收集器调用。

因此,您不能依赖于在终结器中释放非托管资源的时间! 因为它是未知的。

另外,终结器在另一个线程上运行,因此当垃圾回收完成时,终结器可能仍在运行! 因此必须通过另一个垃圾回收来完全摆脱对象。

因此,第一个垃圾回收会调用finalezrs,但是不会收集对象(还有对象所引用的对象),它将在第二个垃圾回收中收集。

具有终结器的对象经历GC的两个阶段:第一次运行终结器,第二次,实际上收集了对象并释放了内存。 除了增加GC压力并延迟将内存释放回池之外,终结器还具有处理其字段可能处于无效状态的对象的功能。 另外,在终结器线程上引发异常会立即破坏整个应用程序,而没有任何关于发生了什么的友好信息。

这就是为什么Dispose模式实现始终以对GC.SuppressFinalize的调用为特征的原因,如果对象已被处置并且GC可以在第一次运行时直接释放内存,则该终结器将无法运行终结器。

通常,如果您的应用程序应能够承受严重异常(例如内存不足或线程异常中止以及随后的AppDomain卸载),则使用终结器可能会非常复杂和棘手。SQLServer或IIS等应用程序就是这种情况。

长话短说:除非绝对必要,否则不要使用终结器,并且如果必须(例如,使用非托管资源),则有很多研究在等待您。

您可以在以下博客文章中找到有关此主题的更多信息:

埃里克·利珀特(Eric Lippert)-当您所知道的一切都不对时

乔·达菲-再也不写终结器了

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM