2013-03-01 16 views
1

它們只是來自node.js官方文檔的幾行內容。這個nodejs代碼是循環引用嗎?

client.on('data', function(data) { 
    console.log(data.toString()); 
    client.end(); 
}); 

我覺得客戶端對象引用了回調,回調函數對客戶端對象有一個閉包引用。那是對的嗎?如果是的話,爲什麼這是鼓勵?

+0

回調函數中的'client'由於範圍而引用原始客戶端,所以除非您重新定義它,否則它不能引用任何其他'客戶端'。這不會導致任何範圍問題,因此可以安全使用。唯一的另一種方式是將客戶端作爲參數傳遞(您無法控制框架所傳遞的內容),或者將客戶端定義在另一個作用域中,如'window',這可能會引入更多問題並且沒有任何改進。 – 2013-03-01 14:29:08

回答

2

是的,這是一個循環引用,但它不是內存泄漏。僅僅給出這個代碼片段,你只有一小部分對象的小圖,但是,只要client可以從主程序到達,所有這些對象將永遠不會有資格進行垃圾回收。但是,如果您要設置client = null;,則包含client對象和匿名事件處理程序函數的對象圖將無法從主程序訪問,因此符合垃圾回收的條件,因此適用於A-OK。

這種模式本身並不是內存泄漏。如果你要在一個循環中創建客戶端,並在一個數組或對象中保留一個對所有這些客戶端的引用,並且沒有代碼來處理陳舊的客戶端,那麼是的,那就是內存泄漏。

+0

謝謝。可能會有更復雜的循環引用。我可以說兩個互相引用的對象,無論是直接的還是間接的,它們都會被V8垃圾回收?只有當其中一個被第三個對象引用時,纔會有內存泄漏? – 2013-03-02 08:31:29

+0

這是正確的。如果從代碼的可運行部分中無法訪問整個大對象圖,那麼整個圖就有資格進行垃圾回收。大多數典型的代碼模式(如上述)不會導致泄漏。在使用對象或數組作爲緩存,地圖,集合等時應保持警惕,因爲這些可能是添加但從不刪除錯誤泄漏的候選對象。 – 2013-03-02 15:09:45

1

這是正確的。 node.js中的事件發射器將其監聽器存儲在私有_listeners屬性中。 您的處理程序函數使用client作爲封閉變量,這並非嚴格必要,因爲所有處理程序都使用事件發件人作爲this引用進行調用。

然而,使用this代替client不會改變的事實,client是在封閉的,因爲它不使用它只是暗示V8取消對它的引用從封閉。

即使從閉包中使用它,V8也有足夠的邏輯來處理這種循環引用並將它們從內存中正確釋放。

+1

謝謝。所以我們不應該擔心這種模式中的循環引用? – 2013-03-02 08:18:45