簡體   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