2011-07-23 73 views
3

最近我一直在閱讀關於內存泄漏的問題,但還沒有把我的腦袋全部包裹起來,並對我自己的寫作風格有一些疑問。具體而言,我不確定我處理事件的方式是否會成爲泄漏的來源。請看下面的代碼事件處理中的內存泄露

function Wrapper(text) { 
    this.text = text; 
    this.bindHandlers(); 
}; 

Wrapper.prototype.onClick = function (e) { 
    alert(this.text); 
}; 

Wrapper.prototype.bindHandlers = function() { 
    var t = this, div = $('<div>' + this.text + '</div>'); 

    var reallyHugeArray = [1,2,3...]; // an array of 100000 elements for example 

    div.click(function (e) { 
     // all variables of the parent function are in scope for this function, including reallyHugeArray 
     t.onClick(e); 
    }); 

    $(document).append(div); 
}; 

var a = new Wrapper('testString'); 

// had enough fun with the Wrapper, now let's nullify it 
a = null; 

正如你所看到的,我喜歡在onClick函數使用匿名函數作爲事件處理程序,以便它可以更方便地訪問特定於實例變量(在這種情況下this.text )和功能。但是,如果我理解正確,在一個函數內部有一個匿名函數(就像事件處理函數一樣),它可以訪問本地作用域,從而禁止垃圾收集器去除局部變量,從而產生泄漏。

所以我的問題是事件處理這種方法是否可以創建內存泄漏,如果是的話,有沒有什麼辦法來防止它,但仍然有方便的相若方式方法來訪問實例變量和函數?

(題外話:在函數內部函數內部功能,使的Javascript聽起來像是以來)

+0

JS和主機對象之間的任何循環引用都可能在IE6/7中創建內存泄漏。這不會在_any體面的瀏覽器中創建泄漏_ – Raynos

+0

您的意思是傳遞給'div.click'的函數不能被垃圾收集器刪除,對吧? – Gumbo

+0

一個名爲'bindHandlers'的函數創建DOM節點並將它們附加到文檔中是錯誤的命名約定 – Raynos

回答

1

在你的具體的例子,匿名點擊處理程序創建它上面的範圍功能關閉。這意味着t,divreallyHugeArray的值在您的匿名點擊處理函數的生命週期中得到維護。

這不是一個真正的內存「泄漏」,而是記憶「用法」。它隨着時間的推移不會變得越來越糟,它只是使用那些本地變量t,divreallyHugeArray佔據的固定量的內存。這通常是JavaScript編程中的一個優勢,因爲這些變量可用於內部函數。但是,正如你所想的那樣,如果你期望內存被釋放,偶爾會導致問題。

在到其他事情(DOM對象或其他JS變量)引用的情況下,由於這些外部變量的繼續,他們指也繼續進行,並且不能被垃圾收集器釋放一切。一般來說,這不是一個大問題。往往會導致問題的事情是隨着網頁被使用或者在一些大循環中進行大量迭代而完成的事情。只有一次這樣執行的東西只需要多使用一次內存,並且從那時起構造的內存使用量就是不變的。

如果由於某種原因,你一遍又一遍結合此事件處理程序再次,每次創建一個新的功能關閉,從不釋放它們,那麼它可能是一個問題。

我覺得這個構造在Javascript中非常有用。我不認爲它是遠離的東西,但是值得理解,以防萬一你想要釋放真正大的事物的引用,那些應該被釋放的瞬態事物,因爲你不需要它們長期的或者你一遍又一遍地做某件事。在這種情況下,如果內部函數中不需要它們來終止它們的引用並允許垃圾回收器執行它,則可以顯式設置局部變量爲null。但是,這不是你通常需要做的事情 - 只是在某些情況下需要注意的事情。

+0

感謝您的出色答案,但是當實例被設置爲'null'的最後一行被執行時會發生什麼。由於有一個綁定到匿名函數的DOM元素,它引用了Wrapper實例,所以我認爲該對象被保留在內存中,因爲我們有一個對它的引用。然後在稍後的時間,如果從DOM中刪除綁定的div,而不移除事件處理程序,那麼變量(t,reallyHugeArray)會被收集還是保留在內存中? (我知道jQuery確實抽象以防止內存泄漏,但假設我沒有使用.remove()) – zatatatata

+0

對不起,之前忘了@ jfriend00。 – zatatatata

+1

@Nanfa原始海報會自動通知回覆,在這種情況下不需要@) –