2012-02-16 79 views
14

我看到通過.on()註冊的事件處理程序存放在$.cache中。 我還看到事件處理程序也在$(elem).data()中。

保存在$.cache中的對象是指事件被註冊的DOM節點。當DOM節點分離時,這導致內存泄漏,並且這使得.off()調用是強制性的。

我有一種情況,我不知道DOM節點(我附加的事件處理程序)何時被分離。雖然我可以在我的代碼中保存對該DOM節點的引用,並調用.off()進行清理,但這看起來不太好,因爲知道何時刪除DOM節點並不簡單。

這樣做的最好方法是什麼?

回答

16

「這樣做的最好方法是什麼?

如果你打算使用jQuery,你必須使用其API用於刪除元素,並且必須使用正確的方法,否則,正如你所說,你就會有內存泄漏。

如果您不知道DOM節點何時被移除,並且它正在導致泄漏,那麼我認爲這意味着您正在使用另一個庫以及jQuery。由於這個原因,這不是一個好主意。

您需要確保受jQuery影響的任何元素都被jQuery刪除。還有一些數據存儲在$.cache中,您沒有明確設置。這意味着所有元素都應該用jQuery去掉,而不僅僅是你認爲認爲可能有數據。


「什麼是$.cache在jQuery的目的是什麼?」

將處理程序和其他數據與元素相關聯。數據和元素之間的鏈接基本上是存儲在元素的expando屬性上的序列號。

如果您刪除沒有jQuery的元素,則$.cache中的關聯數據是孤立的。

這種方法的目的是爲了防止潛在的泄漏。不幸的是,它可能會造成更嚴重的泄漏。

+0

1.如果元素和處理程序之間的關係是通過序列號維護的(如果處理程序沒有引用元素),我沒有看到.cache條目導致內存的原因泄漏。出於某種原因,我不知道它有多合理,緩存條目指的是元素。 我很想知道爲什麼需要引用元素。 2.我不知道元素的expando無法直接保存對對象(處理程序)的引用的情況。如果expando可以容納引用,我並不需要像.cache這樣的並行結構來保存引用。 – user968903 2012-02-16 04:42:25

+0

@ user968903:1.如果您不使用刪除元素時刪除相關的$ .cache條目的jQuery方法,它們只會導致泄漏。序列號是兩者之間唯一的連接,所以如果帶有序列號爲'123'的元素被刪除,但jQuery不會刪除'$ .cache'中的條目'123',那麼該條目現在指的是不再包含數據有一個相應的元素,並且永遠不會被清理。理由是潛在的內存泄漏主要存在於IE6和IE7中。現在,這些瀏覽器幾乎消失了,我不知道這種方法是否好。 – 2012-02-16 14:32:41

+0

@ user968903:2.我認爲現代瀏覽器通常會在刪除元素時進行清理,所以它可能不再是一個問題。我認爲主要是IE6/7有問題。我認爲關於閉包仍然存在潛在的內存泄漏,其中一個元素有一個處理程序在其變量範圍內有一個循環引用,但我不確定這是否是今天的問題。我會看看我能找到什麼。 – 2012-02-16 14:37:20

5

我碰到類似的情況,使用Knockout從文檔中添加和刪除dom樹。但是,jquery用於將事件監聽器附加到這些dom樹上。當knockout從文檔中刪除dom元素時,監聽器不會被綁定,所以dom樹永遠不會被垃圾收集。我們添加了一個清理函數,每次哈希更改時都會遍歷jquery $ .cache,並查找綁定到不在文檔中的樹的處理程序。然後取消綁定監聽器,從而使dom樹有資格進行垃圾回收,並修復我們所看到的大部分泄漏,即現在用於泄露13MB的應用程序的往返行程,現在泄漏只有3MB,並且發生了這些更改。

for (var i in $.cache) { 
      if ($.cache.hasOwnProperty(i)) { 

       if ($.cache[i].handle && $.cache[i].handle.elem && document !== $.cache[i].handle.elem && !jQuery.contains(document, $.cache[i].handle.elem)) { 
        //we have an event handler pointing to a detached dom element! 
        //this is a memory leak as this detached dom element cannot be garbage collected until 
        //all references to it are removed. So lets delete the event handler to get memory back! 
        var orphan = $($.cache[i].handle.elem); 
        $('body').append(orphan); 
        orphan.off(); 
        orphan.remove(); 
        orphan = null; 
       } 
      } 
     } 
+1

看起來像這是基因敲除3.0.0中的一個錯誤的結果,當我升級到3.1.0時,內存泄漏消失了,而不需要上面的代碼! – Troup 2014-07-16 10:40:43