[英]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
,但仍保留對該對象的引用(事件處理程序,靜態字段,局部變量等),則該對象尚不符合收集條件且不會被釋放。
所以,總結一下:
Dispose
通常用於釋放資源(非托管或托管)。 它不以任何方式影響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.