美文网首页
关于闭包在ie浏览器会造成内存泄漏的谣言

关于闭包在ie浏览器会造成内存泄漏的谣言

作者: 前端小学生_f675 | 来源:发表于2019-03-27 11:24 被阅读0次

    最近翻阅文章又看到了这种说法。。。
    23333。。。
    从我接触到前端开始起,这种说法就甚嚣尘上。最常见的说法是闭包在IE浏览器可能会造成内存泄漏;一直不知道为什么,直到读到了曾探的《Javascript设计模式与开发实践》这本书,对该问题有详细的描述和探讨。所以刚入行的前端小伙伴,不要再说这句话了。。。

    谣言止于智者

    局部变量本来应该在函数退出的时候被解除引用,但如果局部变量被封闭在闭包形成的环境中,那么这个局部变量就能一直生存下去。从这个意义上看,闭包的确会使一些数据无法被及时销毁。使用闭包的一部分原因是我们选择主动把一些变量封存在闭包中,因为可能在以后还需要使用这些变量,把这些变量放在闭包中和放在全局作用域,对内存方面的影响是一致的,这里并不能说成是内存泄露。如果在将来需要回收这些变量,我们可以手动把这些变量设为null。

    跟闭包和内存泄露有关系的地方是,使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些DOM节点,这时候就有可能造成内存泄露。但这本身并非闭包的问题,也并非JavaScript的问题。在IE浏览器中,由于BOM和DOM中的对象是使用C++以COM对象的方式实现的,而COM对象的垃圾收集机制采用的是引用计数策略。在基于引用计数策略的垃圾回收机制中,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的。

    Javascript 的垃圾回收机制,我现在知道的有两种:标记、计数。

    标记清除:主流策略,并且与此问题无关。

    引用计数:容易在循环引用时出现问题的策略。因为计数记录的是被引用的次数,所以循环引用时计数并不会消除。导致无法释放内存。IE 9 - 的问题是在环境中bom和dom不是原生的js对象,而是com对象,而com对象的垃圾收集机制是引用计数策略。换句话说,只要ie中存在着com对象,就会存在循环引用的问题。比如

    var element=document.getElementById("someElement");
    var myobject=new Object();
    myobject.element=element;
    element.someObject=myobject;

    这个例子中js对象和dom对象之间建立了循环引用,由于存在这个循环引用,即使将com对象从页面移除,也永远不会被回收。为避免类似问题,应该在不使用它们的时候手动把js对象和com对象断开。

    myobject.element=null;
    element.someObject=null;

    ie9之前的浏览器对javascript对象和com对象使用不用的垃圾收集机制,因此闭包在ie的这些版本中会导致一些特殊的问题
    比如

    function assignHandler(){
    var element=document.getElementById("someElement");
    element.onclick=function(){
    alert(element.Id);
    }
    }
    以上代码创建了一个作为element元素事件处理程序的闭包,这个闭包又创建了一个循环引用,由于匿名函数保存了一个对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数,因此,只要匿名函数存在,element的引用至少是1,因此所占的内存就无法回收,要改下才能解决

    function assignHandler(){
    var element=document.getElementById("someElement");
    var id=element.Id;

    element.onclick=function(){
    alert(id);
    };
    element=null;
    }

    通过把element.Id的副本保存在本地的一个变量中,并且在闭包中引用改变量消除循环引用,但仅仅做到这一步,还不能消除内存泄漏,因为闭包会引用包含函数的整个活动对象,而其中包含着element;即使不直接引用,包含函数的活动对象中仍然保存着一个引用,因此有必要把element变量设置为null。

    同样,如果要解决循环引用带来的内存泄露问题,我们只需要把循环引用中的变量设为null即可。将变量设置为null意味着切断变量与它此前引用的值之间的联系。当垃圾收集器下次运行时,就会删除这些值并回收他们占用的内存。

    所以:内存泄漏是由闭包引起的,闭包表示,老夫不背这个锅。。。233333。。。

    相关文章:
    请详细阅读曾探《Javascript设计模式与开发实践》真心不贵!!!
    京东链接

    相关文章

      网友评论

          本文标题:关于闭包在ie浏览器会造成内存泄漏的谣言

          本文链接:https://www.haomeiwen.com/subject/veoavqtx.html