2010-02-23 115 views
18

我使用jQuery和做这样的事情JavaScript的内存泄漏

DOM

<div id="parent"></div> 

JS

var _doSomeThing = function() 
{ 
    //some codes 
} 

$(function() 
{ 
    // appending div and binding methods to span 
    $('#parent').append('<span>1</span>'); 
    $('#parent').append('<span>2</span>'); 
    $('#parent span').bind('click', _doSomeThing); 
}); 

function _clearDiv() 
{ 
    //clear div 
    $('#parent').html(''); 
} 

//sometime in future, call clear div 
_clearDiv(); 

现在我的问题是,事件绑定到DOM,后来只是从DOM删除元素导致内存泄漏?

如果是的话,该如何解决这个问题?

回答

19

jQuery的html方法试图通过任何元件去除的事件处理程序以防止内存泄漏那由于在jQuery对象上调用.html('')而被删除。

从1.4.2源

html: function(value) { 
    if (value === undefined) { 
     return this[0] && this[0].nodeType === 1 ? 
     this[0].innerHTML.replace(rinlinejQuery, "") : 
      null; 
    } 
    // See if we can take a shortcut and just use innerHTML 
    // THE RELEVANT PART 
    else if (typeof value === "string" && !rnocache.test(value) && 
     (jQuery.support.leadingWhitespace || !rleadingWhitespace.test(value)) && 
     !wrapMap[ (rtagName.exec(value) || ["", ""])[1].toLowerCase() ]) { 

     value = value.replace(rxhtmlTag, fcloseTag); 

     try { 
      for (var i = 0, l = this.length; i < l; i++) { 
       // Remove element nodes and prevent memory leaks 
       if (this[i].nodeType === 1) { 
        jQuery.cleanData(this[i].getElementsByTagName("*")); 
        this[i].innerHTML = value; 
       } 
      } 

     // If using innerHTML throws an exception, use the fallback method 
     } 
     catch(e) { 
      this.empty().append(value); 
     } 
    } 
    else if (jQuery.isFunction(value)) { 
     this.each(function(i){ 
      var self = jQuery(this), old = self.html(); 
      self.empty().append(function(){ 
       return value.call(this, i, old); 
      }); 
     }); 

    } 
    else { 
     this.empty().append(value); 
    } 
    return this; 
} 

我们可以看到,jQuery.cleanData()函数被调用。以下是一个

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

    for (var i = 0, elem; (elem = elems[i]) != null; i++) { 
     id = elem[ jQuery.expando ]; 

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

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

        } else { 
         removeEvent(elem, type, data.handle); 
        } 
       } 
      } 

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

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

      delete cache[ id ]; 
     } 
    } 
} 

这看起来在jQuery.cache对象有关的事件的任何事件类型属性源对象有关主叫.html('')时将被删除,并且删除它们各自元素的数据对象的属性。

要基本解释标准事件绑定是如何工作的,当函数绑定为使用jQuery在元素上引发的事件的处理函数时,会将数据对象作为属性添加到jQuery.cache对象。此数据对象包含一个事件属性对象,该对象将具有在其上创建的属性,其名称与您希望绑定事件处理函数的事件类型匹配。这个属性将包含一个函数数组,这个函数在元素上引发事件时应该被调用,所以事件处理函数被添加到这个数组中。如果这是针对事件类型和元素的第一个事件处理函数,则调用jQuery.event.handle函数(使用元素作为上下文,以使函数执行上下文中的this将引用该元素)向浏览器使用addEventListener/attachEvent

当引发事件时,jQuery.event.handle函数将调用数据对象的events属性对象的属性中匹配事件类型和引发该事件的元素的所有函数。

因此,总之,html('')不应该导致内存泄漏,因为一些防御措施已经到位,以防止它们。

+0

@russ我认为你是对的昨天我做了很多测试,并得出结论.html('');也会避免内存泄漏,而 JS的innerHTML =''会导致内存泄漏。 我想知道是jQuery使内部列表中的元素,我们已经调用$()绑定()函数(即绑定一些事件),以便在window.unload我们可以删除这些事件或jQuery自动为我们做到这一点。对此有任何想法。 – 2010-02-24 07:35:33

+0

jQuery自动绑定一个函数来删除'window.onunload'上的事件处理程序,作为初始脚本执行的一部分。你会在Sizzle代码块之前的1.4.2源代码中找到相关的代码 - http://code.jquery.com/jquery-1.4.2.js :) – 2010-02-24 17:46:00

+0

你是对的,即使是jquery 1.3.2版本清除事件绑定到窗口卸载的元素。 所以我认为我们不必编写我们的代码来清除绑定事件以避免内存泄漏。 thanx – 2010-02-25 19:10:09

2

无法评论泄漏问题,但您可以简单地使用.empty()而不是.html('')。这样你就可以清理innerHTML并删除任何绑定的事件处理程序。

1

您可以随时使用$('#parent span').unbind();只是要确定

2

是的,因为jQuery保持附加事件处理程序的列表,使脱钩他们更容易和以明确解开他们为你当页面卸载(其在IE中更严重的内存泄漏)。 (Prototype也是如此,不能说其他库)。解决方案是在删除元素(直接或通过empty)之前解除它们。

0

由于您经常引用$('#parent'),因此您应该在全局范围内创建对该对象的引用,以便jQuery不会在每个请求中不断查找该对象。这样做,你基本上缓存对象的引用,这将极大地减少内存使用。

_parent = $('#parent'); 

...

function(){ _parent.append('<span>1</span>'); } 

编辑:我从本文拾起此尖端上jQuery Performance Rules

+1

巨大?你有没有分析内存使用前后验证这一说法? – PatrikAkerstrand 2010-02-23 21:47:23

+0

我在jQuery应用程序上有太多内存泄漏,MSIE在10分钟后会自行关闭。进行这一次调整后,泄漏消失并且记忆稳定在合理的量。 – 2010-02-23 22:24:14

+3

我不会称之为内存“泄漏”而不是缓存jQuery对象,但这种做法可能会导致糟糕的性能,这就是您在IE中遇到的情况,这种浏览器系列通常实现的功能更少本地方法('选择器API','document.getElementsByClassName')比其他浏览器,因此需要依靠JavaScript DOM遍历实现来实现相同的结果。我会尽量避免全局命名空间污染,因为它们尽可能地在本地缓存jQuery对象的变量。 – 2010-02-23 22:44:28