论坛首页 Web前端技术论坛

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

浏览 23658 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-08-14  
liudaoru 写道
那么这种情况该如何解释那?这种情况也没有太大的内存泄漏
<div id="bb"><div id="aa">cc</div></div>   
<script type="text/javascript">   
function leakTest(){   
    var a=[];//用来加大闭包资源占用,方便观察   
    for(var i=0;i<100000;i++){   
     a.push('a');   
    }   
    this.divA=document.getElementById('aa');   
    this.divA.kk=function(){};   
   	document.getElementById("bb").removeChild(this.divA);   
}   
new leakTest();   
</script>
 

你确定上面代码,IE下会产生内存泄露?
0 请登录后投票
   发表时间:2008-08-14  
请注意:
  这是楼主的代码,也是会产生内存泄露的代码:
  
<div id="bb"><div id="aa">cc</div></div>  
    <script type="text/javascript">  
    function leakTest(){  
        var a=[];//用来加大闭包资源占用,方便观察  
       for(var i=0;i<100000;i++){  
         a.push('a');  
        }  
       var divA=document.getElementById('aa');  
        divA.kk=function(){};  
       divA.parentNode.removeChild(divA);  
   }  
   leakTest();  
    </script>  

   这是liudaoru的代码,但没有产生内存泄露(不信你可以试试)
  
 <div id="bb"><div id="aa">cc</div></div>     
 <script type="text/javascript">     
 function leakTest(){     
     var a=[];//用来加大闭包资源占用,方便观察     
     for(var i=0;i<100000;i++){     
      a.push('a');     
     }     
     this.divA=document.getElementById('aa');     
     this.divA.kk=function(){};     
     document.getElementById("bb").removeChild(this.divA);     
 }     
 new leakTest();  //产生个匿名对象   
 </script> 


为什么呢?如此相似的代码,一个产生了泄露一个却没有。
个人观点:
楼主用一个var定义了个局部变量divA,闭包<=>div就有了循环引用。
liudaoru用this。this.divA没有被闭包占用(可能是this的特殊性)。于是就有了,匿名对象->divA->闭包,闭包却没有引用diva,也就没有循环引用。
0 请登录后投票
   发表时间:2008-08-22  
achun 写道
有深度呀,第一次看到这样的文章,长知识了。
顺手测试了一下www.jquery.com似乎同样有泄露,
不过我不知道,leaks栏中有红色的和绿色的差别是什么呀?
看来写js还要考虑leak问题呀!
做程序真.....的很...苦......
有泄露就.....要修...补......
啊.........

根据我的经验,红色表示你上次查看(show leaks)后新出现的leaks。
0 请登录后投票
   发表时间:2009-02-05  
这好像是IE的内存管理问题,好像在哪里看到,如果js与js对象互引用不会出现这种情况,如果js与native object互引用特别是用到闭包那这种内存泄露存在的可能性是极高的。
比较可笑的是有人一直去怪IE的内存管理而不去找到让其内存泄露的原因并改之!
0 请登录后投票
   发表时间:2009-02-05  
引用计数的gc方式是不大可能处理js对象和dom对象相互引用的,最好的处理方法是时刻保持清醒即时断开这种互引用就行了。
0 请登录后投票
   发表时间:2009-02-06   最后修改:2009-02-07
trarck 写道
请注意:
  这是楼主的代码,也是会产生内存泄露的代码:
  
<div id="bb"><div id="aa">cc</div></div>  
    <script type="text/javascript">  
    function leakTest(){  
        var a=[];//用来加大闭包资源占用,方便观察  
       for(var i=0;i<100000;i++){  
         a.push('a');  
        }  
       var divA=document.getElementById('aa');  
        divA.kk=function(){};  
       divA.parentNode.removeChild(divA);  
   }  
   leakTest();  
    </script>  

   这是liudaoru的代码,但没有产生内存泄露(不信你可以试试)
  
 <div id="bb"><div id="aa">cc</div></div>     
 <script type="text/javascript">     
 function leakTest(){     
     var a=[];//用来加大闭包资源占用,方便观察     
     for(var i=0;i<100000;i++){     
      a.push('a');     
     }     
     this.divA=document.getElementById('aa');     
     this.divA.kk=function(){};     
     document.getElementById("bb").removeChild(this.divA);     
 }     
 new leakTest();  //产生个匿名对象   
 </script> 


为什么呢?如此相似的代码,一个产生了泄露一个却没有。
个人观点:
楼主用一个var定义了个局部变量divA,闭包<=>div就有了循环引用。
liudaoru用this。this.divA没有被闭包占用(可能是this的特殊性)。于是就有了,匿名对象->divA->闭包,闭包却没有引用diva,也就没有循环引用。


估计是因为闭包只引用函数变量(印象中,闭包是面向函数的编程时引入的概念),而this.divA实际上是leakTest的成员变量(实例变量),是外部可以访问的变量。
所以闭包并没有对this.divA的引用。
如果把上面的第二个代码改成:
 <div id="bb"><div id="aa">cc</div></div>     
 <script type="text/javascript">     
 function leakTest(){     
     var a=[];//用来加大闭包资源占用,方便观察     
     for(var i=0;i<100000;i++){     
      a.push('a');     
     }     
     this.divA=document.getElementById('aa');  
     var self = this.divA;
     this.divA.kk=function(){};     
     document.getElementById("bb").removeChild(this.divA);     
 }     
 new leakTest();  //产生个匿名对象   
 </script> 


这样闭包中有了对self的引用,因此就行成了this.divA对DOM节点( document.getElementById('aa') )的引用,而DOM节点又有对this.divA的引用,这就行成了循环引用(circular reference),资源无法回收。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics