这个javascript模式是否会鼓励内存泄漏?

时间:2013-04-25 14:13:52

标签: javascript jquery

我发现自己对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()被调用;

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

我想知道的是,如果在初始化时缓存元素或对象或其他任何内容,并在应用程序的整个生命周期中引用它们,以上面显示的方式,会对浏览器垃圾收集器产生正面或负面影响。

有什么区别吗?哪种方法最能鼓励垃圾收集?它们会导致泄漏吗?有没有循环参考?如果是这样的话?

1 个答案:

答案 0 :(得分:5)

此代码本身不应导致任何内存泄漏。特别是在现代浏览器中。它只是一个对象,就像你在任何脚本中都有很多其他对象一样。这一切都取决于你引用它的地点,方式和时间。

基本规则是,每当某个对象不再被引用到代码中的任何地方时(直接/通过变量或间接/通过闭包访问范围),GC将标记并滑动。
如果您使用上面的代码,然后将其他内容分配给TEST,则引用的对象文字可以是GC,如果没有其他变量引用原始对象。

当然,预测JS中的内存泄漏是一门不精确的科学。根据我的经验,它们并不像你想象的那么普通。 Firebug,Chrome的控制台(探查器)和IE调试器可以帮助您顺利完成任务。

前段时间我对这件事进行了更多挖掘resulting in this question。也许一些链接和发现对你有帮助......

如果不是,这里有一些提示可以避免明显的泄漏:

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

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