2011-04-11 47 views
10

據我瞭解,在C#垃圾回收器會放一個類的所有對象到結束隊列,只要我實現類的析構函數。當我正在閱讀GC.Suppresfinalize的文檔時,它提到對象頭文件已經有一些設置用於調用finalize。GC爲什麼要將對象放入最終隊列中?

我想知道的是,爲什麼GC的實施者不得不把所有的對象在隊列中,並通過1-2個週期延遲的內存freeup。難道他們不能在釋放內存時查看位標誌,然後調用對象的finalize並釋放內存?

毫無疑問,我是一個白癡,我不能夠理解GC的工作。我提出這個問題只是爲了提高我的理解,或者填補我的知識缺失

編輯:如果位標誌是用於suppressfinalize,GC實現者可能已經在此對象頭中添加了另一個標誌,不是嗎?

+0

哪個實現? – R0MANARMY 2011-04-11 23:45:30

+0

垃圾回收.. – paseena 2011-04-11 23:46:30

+1

我認爲@ R0MANARMY表示哪個GC實現。 Universe中有多個.NET框架的實現。無論如何,哪個實現應該沒有關係,因爲問題是關於爲什麼* GC實現會實現終結器隊列。 – 2011-04-11 23:49:08

回答

11

因此,它可以在不同的線程運行,從而堵塞了主GC線程保持。

你可以學到很多關於此MSDN article的GC。

1

這是理想的垃圾收集暫停要儘可能的短。爲此,當垃圾收集的瘋狂工作完成時,運行終結器通常會延遲到稍後的時間。它是在單獨的線程中在後臺完成的。

+0

這個問題不僅僅是暫停的問題之一,爲了允許存在任意深度的對象圖,許多GC重新使用對象內的內存來跟蹤其進度。他們這樣做的方式可以在GC完成時撤銷,但在GC運行時,許多對象將處於完全不適合運行正常代碼的狀態。 – supercat 2015-12-16 20:24:34

0

@Jason:對於f-reachable隊列是如此。但恕我直言,它並沒有解釋爲什麼有自己的定稿隊列

我的猜測是,終結隊列有加另一個信息,幫助GC 所有對象的生命週期的可能狀態之間進行區分。

對象頭部中的終結標誌表示「對象需要終結」或「對象不需要終結」,但並不表示終止是否已經發生。

但說實話,我不明白爲什麼它需要在當前的定稿過程實施。

事實上,這裏是天真的流程我想可能沒有終結隊列:

  • 創建對象時,如果它有一個終結,則GC設置結束標誌;
  • 如果後來SupressFinalize被調用,那麼該標誌被歸零;
  • 現在讓我們跳到GC收集對象的方式,該對象從任何地方都沒有被引用:如果設置了終結標記,則GC將該對象的引用放入f-reachable隊列,並讓終結線程運行;
  • 後來終結線程退出引用,重置終結標誌並運行終結器;
  • 如果對象想要重新設定以後它可以ReRegisterForFinalize重新設置終止標誌;
  • 後來GC再次收集對象:如果沒有設置終結標誌,它知道沒有什麼要做,然後釋放對象內存;
  • 如果設置了終結標誌,則GC再次將該對象的引用排入f可到達的隊列,然後再次進入另一輪;
  • 在某個時間點對象很高興,完成定稿並收集;或者應用程序域或進程被關閉並且無論如何都釋放內存。

因此,似乎在這些情況下不需要定型隊列,只有定型標誌是有用的。

一個可能的原因是,從概念的角度來看,可能會有一條規則:「一個對象被收集,當且僅當它沒有被任何根引用」。 因此,沒有確定隊列,並且根據對象狀態本身收集對象的決定,檢查確定標誌,與此規則不兼容。

但是我真的不認爲GC的實現是基於這種理論規則的教條性應用,而只是基於實用的選擇;所以很明顯,我錯過了一些關鍵場景,其中GC需要確定隊列才能知道在收集對象時要做什麼,但是哪些是

+0

您預先設定GC查看收集的每個對象。這是沒有必要的,並且使其高效需要向每個對象的頭添加額外的四個字節。 – supercat 2013-10-10 20:57:16

+0

@超級貓:對不起,但我沒有明白你的意思;對我來說,GC必須「查看」它收集的對象,至少要知道它是否必須將它們推送到f-reachable隊列中,或者是否可以刪除它們的內存。爲什麼四個字節?用於存儲散列?因爲對於一個二進制標誌,我想在對象的頭文件中還有一些空閒位。那麼你能否詳細說明這些問題?謝謝。 :) – Pragmateek 2013-10-10 21:28:41

+1

每個有終結器的對象在收集之前都必須查看,但是如果GC有一個包含終結器的所有對象的列表,它只能*查看該列表中的內容。每個活動對象都帶有一個終結器,每個GC週期都必須查看兩次,但死亡對象根本不會被檢查。 – supercat 2013-10-11 00:22:36

1

垃圾收集器不會識別和檢查垃圾,除了處理大對象堆時。相反,它的行爲就像一個保齡球衚衕的取樣器,可以在拋擲之間去除死木:取樣器抓住仍然存在的所有銷釘,將它們從車道表面提起,然後在整個車道上運行清掃杆,而不考慮表面上有多少針腳。清除內存批量比識別要刪除的單個對象快得多。如果1%的對象具有終結器(實數可能更少),那麼有必要檢查100個對象標題以找到每個可終結對象。有一個單獨的具有終結器的對象列表使得GC甚至無需查看任何不包含的垃圾對象。

+1

嗡嗡聲,有趣的點和類比。 :) – Pragmateek 2013-10-11 22:15:55

相關問題