簡體   English   中英

C#Dispose() - 澄清

[英]C# Dispose() -clarification

當我調用object.Dispose() ; CLR會立即從內存中銷毀對象,還是在下一個循環中標記要刪除的對象?

我們在Dispose()之后立即調用GC.SuppressFinalize() ,這是否意味着,“不要再為了dispose收集對象,因為它已經提交給了displose”。

實際上哪一代負責破壞,我猜第2代。

首先, IDisposable.Dispose和GC並不是一回事。

GC將清理內存使用情況, IDisposable.Dispose用於確定性地釋放資源,如文件句柄,數據庫連接,網絡連接等。

讓我們先解決最終問題。

如果一個對象聲明了一個終結器,那么當GC出現以將其從內存中釋放時,該對象將被特別處理。 該對象不是一次被釋放,而是放在一個單獨的列表中。

在后台,終結線程正在運行此列表並調用此列表中對象的終結器方法。 調用終結器方法后,將從列表中刪除該對象。

這里的要點是,雖然對象在此列表中,但它不符合收集條件。 這意味着具有終結器的對象一旦有資格進行收集,將暫時轉換為不再符合收集條件但尚未完成的狀態。 再次發現對象后,在終結器運行並從該列表中刪除后,它將從內存中釋放。

GC.SuppressFinalize只是一個對象說“終結器不再需要運行,如果你發現這個對象有資格收集,只需立即釋放它”的一種方式。

IDisposable.Dispose ,另一方面,一旦由一個對象實現,與垃圾收集器並不完全相關。 GC系統中沒有內置任何內容可確保調用Dispose方法。 這意味着可以輕松釋放具有Dispose方法的對象,而無需調用Dispose

此外,調用Dispose不會以任何方式使對象符合收集條件。 使對象符合收集條件的唯一方法是刪除對它的所有強引用,通常是讓局部變量超出范圍(方法返回),或者從其他對象(如列表,事件處理程序,等等。)

如果要調用它,那么“鏈接”就是內部具有此類資源的對象通常會實現終結器(如果資源是非托管的)。 如果資源是托管的,就像FileStream對象一樣,那么該對象將根據需要自行完成最終化。 但是,如果您要保留非托管資源,例如通過P / Invoke檢索的文件句柄,那么您應該實現終結器。

通常,該對象的終結器和IDisposable.Dispose都將清理該資源,然后它通常用於Dispose調用GC.SuppressFinalize以表示“我已經處理過它,你可以釋放該對象,如果它是有資格領取。“

但是,如果您只是調用Dispose ,但仍保留對該對象的引用(事件處理程序,靜態字段,局部變量等),則該對象尚不符合收集條件且不會被釋放。

所以,總結一下:

  1. 調用Dispose通常用於釋放資源(非托管或托管)。 以任何方式影響GC是否可以收集對象,或將於何時完成。
  2. 使對象符合收集條件的唯一方法是明確丟失對它的所有強引用。
  3. GC調用終結器,通常用於釋放非托管資源。
  4. 有資格收集但有終結器的對象將暫時放在列表中(因此不再有資格收集),直到終結器被執行

獎金問題

如果出現以下情況,您認為會怎樣?

  1. 終結者掛了嗎? (通常(據我所知)只有一個終結器線程,如果它掛起,該列表上其余對象會發生什么?)
  2. 一個對象使自己無法收集作為其終結器的一部分(通常通過將自身插入到靜態字段中)。 終結器已經運行,並且有一個標記,因此一旦對象再次可用於收集,終結器將不會自動重新運行。 GC對象中還有其他方法可以重新注冊它以進行最終確定。

希望這能回答你的問題,如果沒有,請發表評論或澄清你的問題,我會編輯我的答案。

Dispose是一種正常的CLR方法,恰好通常調用GC.SuppressFinalize 垃圾收集器與它無關,調用Dispose對GC沒有特殊意義。

如果Dispose調用GC.SuppressFinalize(this) ,則GC在收集對象時不會運行終結器。
但是,這並不意味着將盡快收集對象。

不, Dispose不會導致垃圾收集器收集對象。 您在許多Dispose方法中看到GC.SuppressFinalize()的原因是因為許多一次性類實現了終結器以確保處置。 我會解釋一下。

如果我實現了擁有關鍵資源類,我想確保 (好,幾乎可以肯定),我的類進行適當處理,那么我可能不會僅僅依靠消費者我的課的叫Dispose或使用using 相反,我可以實現一個終結器,在大多數情況下,當GC收集我的對象時會調用它。 在終結器中,我將強制調用Dispose

但是具有終結器的對象對於垃圾收集器來說更復雜。 它會更長時間地停留,占用更多內存,並且在收集時需要更多時間來處理。

因此,如果用戶確實記得正確處置,那么我們可以告訴GC它不需要為此對象調用終結器。

對象的生成是指它“幸存”了多少垃圾收集(2是最高的)。 當一個對象被創建時,它在第0代,並且只有當對象在收集時可以訪問或“實時”(具有強引用)時才會被提議用於下一代。

這不包括具有復雜終結器的第0代對象,因為終結器在單獨的線程上運行並且一旦完成,就以通常的方式收集。 他們沒有升職。

第2代對象的收集可能需要很長時間,因為GC可能只需要收集第0代對象以釋放堆上足夠的空間。 要強制完整集合,請調用GC.Collect()。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM