2011-08-25 69 views
13

我正在用大量的JavaScript處理大型企業應用程序。足夠我不可能通過並修復所有在過去5年的開發過程中創建的小型循環引用。雖然研究解決方案,我遇到了這個小jQuery的黑客/補丁:解決了jQuery泄漏問題,但爲什麼?

http://kossovsky.net/index.php/2009/07/ie-memory-leak-jquery-garbage-collector/

,並決定嘗試一下。令人驚訝的是,它的工作原理! sVEVE在我之前識別它們的地方顯示沒有泄漏,並且iexplore任務保持了更易於管理的內存佔用。

我的問題是,這是爲什麼這樣工作? jQuery.remove調用.removeChild,這應該擺脫元素,但顯然不。該補丁改爲將目標元素追加到新的垃圾回收器div上,然後清除它。爲什麼刪除的補丁方法完全釋放內存,但jQuery的刪除功能沒有?我希望能夠理解爲什麼這會起作用,以便在我檢查到更大的應用程序之前改進解決方案。

回答

12

這是當前jQuery版本(1.6.2)中的.remove方法。請注意,它調用.cleanData

// keepData is for internal use only--do not document 
    remove: function(selector, keepData) { 
     for (var i = 0, elem; (elem = this[i]) != null; i++) { 
      if (!selector || jQuery.filter(selector, [ elem ]).length) { 
       if (!keepData && elem.nodeType === 1) { 
        jQuery.cleanData(elem.getElementsByTagName("*")); 
        jQuery.cleanData([ elem ]); 
       } 

       if (elem.parentNode) { 
        elem.parentNode.removeChild(elem); 
       } 
      } 
     } 

     return this; 
    }, 

而且.cleanData方法,它調用,其中提到一個票號,據稱防止可怕的泄漏(根據意見之一):

cleanData: function(elems) { 
     var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special, 
      deleteExpando = jQuery.support.deleteExpando; 

     for (var i = 0, elem; (elem = elems[i]) != null; i++) { 
      if (elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) { 
       continue; 
      } 

      id = elem[ jQuery.expando ]; 

      if (id) { 
       data = cache[ id ] && cache[ id ][ internalKey ]; 

       if (data && data.events) { 
        for (var type in data.events) { 
         if (special[ type ]) { 
          jQuery.event.remove(elem, type); 

         // This is a shortcut to avoid jQuery.event.remove's overhead 
         } else { 
          jQuery.removeEvent(elem, type, data.handle); 
         } 
        } 

        // Null the DOM reference to avoid IE6/7/8 leak (#7054) 
        if (data.handle) { 
         data.handle.elem = null; 
        } 
       } 

       if (deleteExpando) { 
        delete elem[ jQuery.expando ]; 

       } else if (elem.removeAttribute) { 
        elem.removeAttribute(jQuery.expando); 
       } 

       delete cache[ id ]; 
      } 
     } 
    } 

這裏是評論中提到的票。顯然,這是八個月前固定:

http://bugs.jquery.com/ticket/7054#comment:10

據戴夫Methvin的解決方案似乎是確保在事件處理程序的DOM元素裁判通過cleanData去除,以避免IE6/7/8內存泄漏。

換言之,設定事件處理程序內,以DOM元素的引用到null否則一些真棒瀏覽器,沒有提及任何名字咳嗽 IE 咳嗽將泄漏內存。

discardElement(從您的鏈接中)將元素插入到容器中,然後清空容器,從而取消爲對該元素的任何引用。

考慮到這一點,我會建議升級jQuery。您指出的文章是從2009年開始的,兩年大致相當於4.0億人小時的jQuery開發時間。

最後,這裏是泄漏模式的一些有趣(和可笑長)讀數在Internet Explorer中:

+0

可惜我不能合理地去完成整個代碼庫尋找事件處理程序爲空。這就是爲什麼這個駭人聽聞的解決方案吸引我。只要它被證明是一個銀色的子彈,不需要手動設置處理程序爲空。 – JPRO

+0

@JPRO - 不是事件處理程序,事件處理程序中的DOM元素,如果您願意將jQuery升級到更新版本,則不必這樣做。 – karim79

+0

當然,不好的代碼一直是這個問題的一個主要原因,我可以通過它並糾正它,但這需要比我爲這項任務分配更多的時間。我們目前正在使用jQuery 1.6.2。這就是說,我認爲你已經回答了爲什麼這種方式有效(我自己也得出了同樣的結論,但希望得到更多的意見)。謝謝(你的)信息! – JPRO

1

我在理論上認爲它與.net垃圾收集類似,因爲它依賴於堆中的固定對象。

IE正在處理被刪除的對象的父級,例如針,而不是正確清除已刪除的對象。

將刪除的項目移動到這個生成的gc容器的行爲基本上是刪除了pin,因爲IE知道沒有任何東西依賴於該容器。

無論如何,這是我的直覺。