2 回答

TA貢獻1864條經驗 獲得超2個贊
Konrad Kokosa 在他的《Pro .NET Memory Management 》一書中有一個令人印象深刻的解釋。(強調)
在 GC 期間,在標記階段結束時,GC 檢查終結隊列以查看是否有任何可終結對象已死亡。如果它們是一些,它們還不能被刪除,因為它們的終結器需要被執行。因此,這樣的對象被移動到另一個名為 fReachable queue 的隊列。它的名字來自于它代表最終化可達對象的事實——那些現在只因為最終化才可達的對象。如果找到任何此類對象,GC 會向專用終結器線程指示有工作要做。
終結線程是由 .NET 運行時創建的另一個線程。它從 fReachable 隊列中一個一個地移除對象并調用它們的終結器。這發生在 GC 恢復托管線程之后,因為終結器代碼可能需要分配對象。由于此對象的唯一根已從 fReachable 隊列中刪除,下一次譴責此對象所在世代的 GC 將發現它不可訪問并回收它。
此外,fReachable 隊列在 Mark 階段被視為根,因為終結器線程可能不夠快,無法在 GC 之間處理來自它的所有對象。這使可終結對象更多地暴露于中年危機——它們可能會停留在 fReachable 隊列中一段時間,僅僅因為等待終結而消耗第 2 代。
我認為這里的關鍵是:
fReachable 隊列在 Mark 階段被視為根,因為終結器線程可能不夠快,無法在 GC 之間處理來自它的所有對象。

TA貢獻1785條經驗 獲得超8個贊
.NET 中的對象在存在對它們的任何引用時就存在。一旦最后一個引用不存在,它們就會不復存在。當對象存在時,對象使用的存儲將永遠不會被回收,但是 GC 在回收存儲之前會做幾件事:
有一個特殊的列表,稱為“終結器隊列”,它包含對所有已注冊終結器的對象的引用。在識別出 Universe 中任何地方存在的所有其他引用之后,GC 將檢查終結器隊列中的所有對象,以查看是否找到了對它們的任何引用。如果此過程導致它找到以前未發現的對象,它會將引用復制到另一個稱為“freachable 隊列”的列表。任何時候 freachable 隊列非空并且沒有終結器正在運行,系統將從該隊列中提取一個引用并調用終結器。
GC 還將檢查所有弱引用的目標,并使目標未被任何有效強引用識別的任何弱引用無效。
請注意,finalize 方法不會“垃圾收集”對象。相反,它會延長對象的存在直到finalize
被調用,目的是允許它履行對外部實體可能具有的任何義務。如果那時在宇宙中任何地方都不存在對該對象的引用,則該對象將不復存在。
請注意,兩個具有終結器的對象可能會相互引用。在這種情況下,它們的終結器運行的順序是未指定的。
- 2 回答
- 0 關注
- 127 瀏覽
添加回答
舉報