1

我发现自己对 javascript 垃圾收集以及如何最好地鼓励它感到很困惑。

我想知道的是与特定模式有关。我对模式本身是否被认为是一个好主意或坏主意不感兴趣,我只是对浏览器垃圾收集器将如何响应感兴趣,即引用会被释放和收集还是会导致泄漏。

想象一下这种模式:

   TEST = {     
                init : function(){                        
                      this.cache = {
                           element : $('#element')
                      };
                },
                func1 : function(){
                       this.cache.element.show();                     
                },
                func2 : function(){                                            
                       TEST.cache.element.show(); 
                },
                func3 : function(){
                       var self = this;                      
                       self.cache.element.show(); 
                },
                func4 : function(){
                       var element = this.cache.element;
                       element.show();
                }
                func5 : function(){
                        this.auxfunc(this.cache.element);
                }
                auxfunc1 : function(el){
                         el.show();
                }
                func6 : function(){
                       var el = getElement();
                       el.show();
                }
                getElement : function(){
                       return this.cache.element;
                }
    }

现在想象一下页面加载TEST.init()被调用;

然后在不同的时间调用各种函数。

我想知道的是,在初始化时缓存元素或对象或其他任何东西,并以上述方式在应用程序的整个生命周期中引用它们,是否会对浏览器的垃圾收集器产生积极或消极的影响。

有什么区别吗?哪种方法最能鼓励垃圾收集?它们会导致泄漏吗?有没有循环引用?如果是在哪里?

4

1 回答 1

5

此代码本身不应导致任何内存泄漏。尤其是在现代浏览器中。它只是一个对象,就像您在任何脚本中都有大量其他对象一样。这完全取决于您引用它的位置、方式和时间。

基本规则是,只要在代码中的任何位置(直接/通过变量或间接/通过闭包访问范围)不再引用对象时,GC 将标记并滑动。
如果您使用上面的代码,然后将其他内容分配给TEST它引用的对象文字,则如果没有其他变量引用原始对象,则它可能会被 GC'ed。

当然,预测 JS 中的内存泄漏是一门不精确的科学。根据我的经验,它们并不像某些人让你相信的那么普遍。Firebug、Chrome 的控制台(分析器)和 IE 调试器让您一路走好。

前段时间我对这件事做了更多的研究,导致了这个问题。也许一些链接和发现对你有帮助......

如果不是,这里有几个技巧可以避免明显的泄漏:

  • 不要使用全局变量(它们实际上不会永久泄漏内存,但只要您的脚本运行就这样做)。
  • 不要将事件处理程序附加到全局对象(window.onload==> 在 IE <9 中泄漏 mem,因为全局对象永远不会完全卸载,因此事件处理程序不是 GC'ed)
  • 只需将您的脚本包装在一个巨大的 IIFE 中,并尽可能使用严​​格模式。这样,您创建了一个可以在卸载时完全 GC 的作用域。
  • 测试,测试,再测试。不要相信你读过的关于这个主题的每一篇博文!如果去年有什么问题,那么今天就不一定了。当你读到这篇文章时,这个答案可能不再是 100% 准确,或者因为就在今天早上 JS GC'ing 的一些奇迹补丁是由 erm...Paris Hilton 或其他一些外星生命形式编写的。

哦,回答你的评论中的问题:“但我担心的是,如果每次我调用 this.cache.element,它是否会在原始缓存引用的顶部的函数范围内创建一个新引用,这不会是垃圾集?”
答案是不。因为this将引用该TEST对象,并且该init函数为该对象分配了一个 property cahche,所以它本身就是另一个对象字面量,其中 1 个属性引用了一个 jQ 对象。该属性 ( cache) 以及通过它可访问的所有内容将一直保存在内存中,直到您选择delete TEST.cachedelete TEST。如果您要创建var cahce = {...};该对象,那么当ini函数返回,因为变量不能超过其范围,除非您使用闭包并间接公开某些变量。

于 2013-04-25T14:19:16.080 回答