IE下闭包引起跨页面内存泄露探讨

来源:互联网 发布:淘宝上的葡萄酒怎么样 编辑:程序博客网 时间:2024/06/05 00:29

IE下闭包引起跨页面内存泄露探讨

 

ie的内存泄露中跨页面的泄露是最严重的,浏览器刷新了仍然无法释放掉泄露占用的资源,造成访问速度越来越慢,内存占用越来越大
closure引起cross page leak的主要原因是closure和dom元素的互相引用
看这个例子:

Java代码 复制代码
  1. <div id="bb"><div id="aa">cc</div></div>   
  2. <script type="text/javascript">   
  3. function leakTest(){   
  4.     var a=[];//用来加大闭包资源占用,方便观察   
  5.     for(var i=0;i<100000;i++){   
  6.      a.push('a');   
  7.     }   
  8.     var divA=document.getElementById('aa');   
  9.     divA.kk=function(){};   
  10.     divA.parentNode.removeChild(divA);   
  11. }   
  12. leakTest();   
  13. </script>  


    用sIEve看下发现这个页面每次刷新都会产生跨页面泄露,ie内存占用大了7MB,具体fins的文章中有过介绍
在这个例子中我们在leakTest()中创建了一个内部匿名函数并在dom元素aa的自定义属性kk中保存了他的引用,这就产生了一个闭包
divA.parentNode.removeChild(divA);
这句是产生泄露的主要原因,移除了aa并不会使这个节点消失,只不过在dom树上无法访问这个节点而已,由于闭包的存在divA这个局部变量不会被释放,而divA中保存着aa的引用,这就形成了一个循环引用,闭包保存了dom元素aa的引用,dom元素aa的自定义属性kk又保存了闭包内部的匿名函数的引用,所以在页面刷新的时候IE无法释放掉这个aa和闭包的资源,在我这个例子中就比较吓人,刷一下涨几MB内存
    让我们删掉divA.parentNode.removeChild(divA);这句试试,发现没有泄露发生
    我推测IE在刷新时会强行释放掉dom树上的元素,而不存在于dom树中的节点不会强行释放,所以造成了跨页面泄露,这是我的个人推测,有别的意见欢迎讨论
怎么解决这个问题呢,其实我们只要打断引用链就行了

Java代码 复制代码
  1. <div id="bb"><div id="aa">cc</div></div>   
  2. <script type="text/javascript">   
  3. function leakTest(){   
  4.     var a=[];   
  5.     for(var i=0;i<100000;i++){   
  6.      a.push('a');   
  7.     }   
  8.     var divA=document.getElementById('aa');   
  9.     divA.kk=function(){};   
  10.     divA.parentNode.removeChild(divA);   
  11.     divA=null;   
  12. }   
  13. leakTest();   
  14. </script>  


或者

Java代码 复制代码
  1. <div id="bb"><div id="aa">cc</div></div>   
  2. <script type="text/javascript">   
  3. function leakTest(){   
  4.     var a=[];   
  5.     for(var i=0;i<100000;i++){   
  6.      a.push('a');   
  7.     }   
  8.     document.getElementById('aa').kk=function(){};   
  9.     document.getElementById('aa').parentNode.removeChild(document.getElementById('aa'));   
  10.     //这个例子不保存aa的应用,也不会引起泄露   
  11. }   
  12. leakTest();   
  13. </script>  


or

Java代码 复制代码
  1. <div id="bb"><div id="aa">cc</div></div>   
  2. <script type="text/javascript">   
  3. function leakTest(){   
  4.     var a=[];   
  5.     for(var i=0;i<100000;i++){   
  6.      a.push('a');   
  7.     }   
  8.     var divA=document.getElementById('aa');   
  9.     divA.kk=function(){};   
  10.     divA.parentNode.removeChild(divA);   
  11.     return divA;   
  12. }   
  13. var divA=leakTest();   
  14. divA.kk=null//这个可以看到内存占用比上面少了7MB,因为解除了对闭包内部函数的引用,闭包占用的资源被释放了   
  15. </script>  


通过上面的例子可以看出,如果某个函数中dom元素保存了内部函数的引用,就会形成闭包,很容易引起泄露,务必小心
另firefox下测试是没有这些问题的

原创粉丝点击