【问题标题】:Using jQuery and Memory Leaks使用 jQuery 和内存泄漏
【发布时间】:2011-03-11 02:30:45
【问题描述】:

我已经使用 jQuery 两个多月了,并阅读了几天关于 Javascript 内存泄漏的信息。 我有两个关于内存泄漏和 jQuery 的问题:

  1. 当我绑定(使用 .bind(...))时,如果我离开页面/刷新以避免内存泄漏,是否必须解除绑定(.unbind()),还是 jQuery 会为我删除它们?

  2. 关于闭包,我读到如果使用不当,它们会导致内存泄漏。如果我这样做:

    function doStuff( objects ){ //objects 是一个 jQuery 对象,它包含一个 DOM 对象数组 var textColor = "红色"; 对象.每个(函数(){ $(this).css("color", textColor); }); }

    doStuff($("*"));

我知道上面的代码很愚蠢(更好/更简单的方法)但我想知道这是否会导致 .each 的循环引用/关闭问题以及是否会导致内存泄漏。如果确实导致内存泄漏,我将如何重写它(通常是类似的方法)以避免内存泄漏?

提前致谢。

编辑:我有另一个类似于问题 2 的案例(我猜这会成为第 3 部分)。

  1. 如果有这样的事情:

    function doStuff( objects ){ //iframe 对象 var textColor = "红色";

    function innerFunction()
    {          
        $(this).contents().find('a').css("color", textColor );
    }
    
    objects.each(function(){   
        //I can tell if all 3 are running then we 
        //have 3 of the same events on each object, 
        //this is just so see which method works/preferred
    
        //Case 1
        $(this).load(innerFunction);
    
        //Case 2
        $(this).load(function(){
           $(this).contents().find('a').css("color", textColor );
        });
    
        //Case 3  
        $(this).load(function(){
           innerFunction();
        });
    });
    

    }
    doStuff($("iframe"));

上面有 3 种情况,我想知道哪种方法(或所有方法)会产生内存泄漏。另外我想知道哪种方法是首选方法(通常我使用案例 2)或更好的做法(或者如果这些方法不好,那会更好吗?)。

再次感谢!

【问题讨论】:

    标签: javascript memory-leaks closures jquery


    【解决方案1】:

    1) 不会。浏览器会在页面加载之间清除所有内容。

    2) 在当前形式下不会有内存泄漏,因为 jquery 的 .each() 函数没有绑定任何东西,所以一旦它执行完成,它传递的匿名函数就不再可访问,因此环境它已关闭(即整个关闭)也无法访问。所以垃圾收集引擎可以清理一切——包括对objects的引用。

    但是,如果你有一些无害的东西而不是 .each(),例如 $('div:eq(0)').bind()(我试图强调它不必是对大的 objects 变量的引用,它甚至是一个单一的无关元素),那么由于发送到.bind() 的匿名函数关闭了objects 变量,它将保持可访问性,因此不会被垃圾回收,从而导致内存泄漏。

    避免这个问题的一个简单方法是在执行函数的末尾objects = null;

    我应该注意,我不熟悉 JS 垃圾收集引擎,因此可能存在相当智能的优化。例如,可以检查匿名函数是否尝试访问任何用它关闭的变量,如果没有,它可能会将它们传递给垃圾收集器,这将解决问题。

    如需进一步阅读,请查找对 javascript 内存模型的引用,特别是环境模型和静态绑定。

    【讨论】:

      【解决方案2】:

      有一些您甚至可能无法识别的细微泄漏模式。查看我前段时间就类似问题提出的问题 jQuery 1.5 Memory leak in IE8

      如果你在一个引用 dom 节点的对象周围创建一个闭包,就会产生一个泄漏的引用循环,不幸的是,它不能通过简单地解除绑定来纠正。您必须将对象中对 DOM 节点的引用设置为 null。

      【讨论】:

      • 我不同意,仅仅因为有一个对象引用了一些 DOM 节点,并不意味着存在泄漏。在这种特殊情况下,对象在函数执行结束时不再可访问,因此可以进行垃圾回收 ==> 没有内存泄漏。
      • 理论上是这样的。但是在某些情况下,一旦在 IE (object->node->eventHandler->object) 中创建了引用循环,即使您分离 eventHandler (object->node X eventHandler->object),它也永远不会被释放。 )。请尝试我提供的链接中的 jsFiddle 并观看 taskManager
      • 这里的代码中没有循环引用,所以虽然你在这种情况下可能是对的,但它在这里不适用。
      • 有意思,能举个jordan的例子吗?这会导致泄漏吗? var test = $('#id').click(function(){$(this).hide();});
      • 这不会泄漏,因为没有关闭。然而这会var test = {}; test.node = $('#id'); test.node.bind('click',function(){})); test.node.remove();你可以循环这个100次左右,然后看着内存上升。
      【解决方案3】:

      关于 1.,不,您在离开页面时绝对不必.unbind()。我不太确定有两个。

      【讨论】:

        【解决方案4】:

        关于 1,有时您必须释放资源,尤其是当您有循环引用并使用 Internet Explorer 时(由于一些错误,因为理论上您不应该这样做);)谷歌地图在他们的v2 以防止我们不得不调用 document.onunload (GUnload)。

        关于 2,您没有循环引用。它消耗大量内存,因为this 必须有自己的执行上下文才能访问textColor 等等。

        当对象引用自身或闭包调用自身时,实现循环引用。也许还有其他情况..

        希望对你有帮助

        【讨论】:

        • 你可以在没有循环引用的情况下通过闭包导致泄漏
        猜你喜欢
        • 2013-04-02
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多