代码之家  ›  专栏  ›  技术社区  ›  Bob Fincheimer

JQuery垃圾收集-这会是干净的吗?

  •  15
  • Bob Fincheimer  · 技术社区  · 14 年前

    许多文章(例如。 msdn )已经说过循环引用在某些浏览器中涉及 多姆 对象和

    (IE6根本无法完成,IE7只能在页面请求之间完成):

    Javascript本机( 泄漏 ):

    function leak(){
        var elem = document.createElement("DIV");
        document.body.appendChild(elem);
        elem.onclick = function () {
            elem.innerHTML = elem.innerHTML + ".";
            // ...
        };
    }
    

    因为元素的onload属性通过闭包引用回自身,所以它创建了一个 循环引用 :

    elem [DOM] -> elem.onclick [JS] -> elem [DOM]

    JQuery版本( ):

    function leak(){
        var elem = $('<div></div>');
        $(document.body).append(elem);
        elem.click(function () {
            elem.html(elem.html() + ".");
            // ...
        };
    }
    

    elem [JS] -> element [DOM] -> elem.onclick [JS] -> elem [JS]

    3 回复  |  直到 13 年前
        1
  •  6
  •   Waynn Lue    13 年前

    jQuery代码中的最后一件事(在Sizzle代码之前,它的选择器引擎)是这样的(这是防止泄漏的代码):

    // Prevent memory leaks in IE
    // Window isn't included so as not to unbind existing unload events
    // More info:
    //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
    if ( window.attachEvent && !window.addEventListener ) {
        window.attachEvent("onunload", function() {
            for ( var id in jQuery.cache ) {
                if ( jQuery.cache[ id ].handle ) {
                    // Try/Catch is to handle iframes being unloaded, see #4280
                    try {
                        jQuery.event.remove( jQuery.cache[ id ].handle.elem   );
                    } catch(e) {}
                }
            }
        });
    }
    

    当您在jQuery中执行任何操作时,它既存储了它所做的操作(即函数),也存储了它所做的操作(即DOM元素)。onunload通过jQuery缓存从它自己的内部缓存的事件处理程序中删除函数(不管怎样,事件都存储在这里,而不是存储在单个DOM节点上)。

    if ( window.attachEvent && !window.addEventListener ) {
    

    确保它只在IE上运行。

        2
  •  2
  •   Pointy    14 年前

    当您通过库执行所有操作时,JQuery只能确保没有泄漏。jQuery中有一些称为“empty”和“cleanData”的例程,您可以仔细阅读这些例程以查看到底发生了什么,但基本上,代码只是在释放DOM元素之前将它所知道的一切从DOM元素中分离出来。当您执行诸如用“.html()”或“.load()”覆盖元素内容之类的操作时,将调用该例程。

    就我个人而言,在这种情况下,我对“担保”这样的术语相当谨慎。

        3
  •  1
  •   BGerrissen    14 年前

    重写以进一步澄清

    直接的 对闭包中活动DOM节点的引用。垃圾收集器(JS&传统浏览器(如IE6)的DOM)不能使这些引用无效。因此,需要在函数末尾取消节点引用。

    jQuery在默认情况下避免了这一点,因为活动DOM元素作为属性/属性附加到jQuery对象,通过这些属性,上述垃圾收集器可以轻松确定空引用。如果jQuery对象有空引用,那么它将被简单地清除,并且它的属性/属性(在本例中是对活动DOM元素的引用)也会随之清除。

    因此,为了避免这种内存泄漏,需要让一个对象维护对活动DOM节点的引用,然后在闭包中引用该对象。闭包将只维护对对象的引用,而不维护活动DOM元素,因为该引用属于该对象。

    // will still leak, but not due to closure references, thats solved.
    function noLeak(){
        var obj= {
            elem: document.createElement('div')
        }
        obj.elem.onclick = function(){
            obj.elem.innerHTML = obj.elem.innerHTML + ".";
        }
    }
    

    addEvent

    为事件系统创建包装器会增加一些代码,但这是必不可少的。其主要思想是添加一个通用的eventHandler,将事件委托给存储所需引用的事件缓存/系统。在unload事件中,缓存被清除,打破循环引用,允许垃圾收集器(JS和DOM)整理自己的角落。