30

有人可以詳細解釋Javascript引擎如何處理循環引用?瀏覽器甚至node.js有很大的區別嗎?Javascript /垃圾回收器中的循環引用

我在說的是對象內的明確的後/後引用。例如:

var objA = { 
    prop: "foo", 
    next: null 
}; 

var objB = { 
    prop: "foo", 
    prev: null 
}; 

objA.next = objB; 
objB.prev = objA; 

我們走了。如果我們做一個console.log(objA)我們可以看到我們創建了一個無限的鏈。 最大的問題是,這不好嗎?未明確清理時是否會造成內存泄漏?

那麼我們必須

objA.next = null; 
objB.prev = null; 

或將垃圾收集在這樣的星座照顧我們?

回答

53

任何半面體垃圾收集器都會處理週期。

如果您進行天真的引用計數,週期只是一個問題。

大多數垃圾收集器不會進行重新計數(因爲它無法處理循環,並且效率低下)。相反,他們只需遵循他們可以找到的每個參考,從「根」(通常是全局變量和基於堆棧的變量)開始,並將他們可以找到的所有內容標記爲「可達」。

然後他們只是回收所有其他內存。

週期沒有問題,因爲它們只是表示同一個節點將被多次訪問。在第一次之後,節點已經被標記爲「可達」,並且GC將知道它已經在那裏,並跳過該節點。

基於引用計數的更原始的GC通常實現檢測和中斷週期的算法。

總之,這不是你必須擔心的。我似乎記得IE6的Javascript GC實際上沒有處理週期(我可能錯了,自從我閱讀它已經有一段時間了,而且自從我碰到IE6以來已經很長時間了),但是在任何現代實現中,它都是沒問題。

垃圾回收器中的整個點是抽象出內存管理。如果你必須自己做這個工作,你的GC壞了。

請參閱MDN瞭解更多關於現代垃圾收集和所使用的標記 - 掃描算法的信息。

+1

http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Closures那該怎麼辦? – Sandro

+2

@Sandro再次閱讀我的答案。 :)一個理智的GC處理週期就好了。所有比IE6更新的東西都可以被認爲是理智的。如果你需要支持IE6,那麼你不得不擔心它的循環處理中斷。顯然,Google的指南是在這樣的假設下編寫的,即必須支持這些破碎的瀏覽器,所以他們不得不跳過一些額外的環節。 – jalf

+0

@Sandro在這個例子中有一些特殊的情況:DOM元素是循環引用的一部分。一般來說,你會泄漏內存,直到你關閉頁面。但是,如果我記得正確,那麼當您離開時,IE並不總是刪除對DOM的引用。 (顯然這樣做打破了一些頁面?) –