2011-01-12 61 views
5

儘管我認爲我理解問題的要點(即一個好的GC跟蹤對象,而不是範圍),但我不太瞭解該主題以說服其他人。爲什麼RAII和垃圾收集相互排斥?

你可以給我一個解釋,爲什麼沒有垃圾收集語言與確定性的析構函數?

+0

-1問題是錯誤的。有確定性析構函數的垃圾收集語言,例如.NET上的「IDisposable」爲C#,VB.NET和F#提供了確定性的破壞。 – 2012-06-19 20:06:00

回答

3

它們不是相互排斥的。隨意使用C++與libgc(Boehm-Reiser-Detlefs收集器)。您仍然可以使用RAII,智能指針和手動刪除,但在GC運行時,您也可以「忘記」刪除一些對象。

@ Andy對於資源處理得太晚的回答忽略了一個重要的觀點:它不是延遲釋放在語義上至關重要的資源,而是釋放的順序。

GC傾向於不順序釋放的原因是它需要對排序要求(依賴性)進行拓撲排序,這是一個昂貴的算法。

儘管Ocaml GC有一個有趣的設施,您可以在其中附加一個終結器到一個對象。如果對象變得無法訪問,則終結器將運行,但是該對象不會被刪除(因爲終結器可以使其再次可達:在這種情況下,您甚至可以連接另一個終結器)。這些終結者可以提供對訂購的一些控制。

0

Wikipedia指出,追查垃圾收集器是最常見的類型後:

追蹤垃圾回收不確定性 。一個對象變成 有資格進行垃圾回收,最終通常會清理掉 ,但是 沒有保證的時候(或者甚至是 if)會發生。

因此,依靠RAII可能會導致資源被處置得太晚。因此,例如,Java有一個「避免終結器」(Josua Bloch的「Effective Java」中的第6項)的指導原則。 「終結者永遠不應該做任何時間批判。」

+0

FWIW關於垃圾收集的維基百科頁面大多是錯誤的,包括該部分。 – 2012-02-05 09:34:27

+0

@JonHarrop - 對這個答案的任何具體批評都歡迎。 – 2016-04-18 02:39:51

0

垃圾收集器不能一直運行(refcounting越來越近,但通常不會算作垃圾收集),所以它甚至不嘗試。這顯然不切實際。因此,在對象變得無法訪問(例如因爲唯一的引用超出範圍)和GC收集對象之間存在不可避免的延遲,可能觸發終結器。這種延遲不是確定性的,除非(然後,儘可能嚴格意義上的確定性破壞是可能的,儘管仍然不切實際)迫使GC進入確定性時間表 - 但這非常接近「GC始終在運行」 ,這仍然非常不切實際。

因此,GC和確定性清理是相互排斥的,因爲GC執行所有清理並且無法承擔確定性,但必須依靠最大化其效率。