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

引:http://www.javaeye.com/topic/180611

 

在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>  
<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> 

    用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>  
<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); 	divA=null; } leakTest(); </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>  
<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'); 	} 	document.getElementById('aa').kk=function(){}; 	document.getElementById('aa').parentNode.removeChild(document.getElementById('aa')); 	//这个例子不保存aa的应用,也不会引起泄露 } leakTest(); </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>  
<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); 	return divA; } var divA=leakTest(); divA.kk=null; //这个可以看到内存占用比上面少了7MB,因为解除了对闭包内部函数的引用,闭包占用的资源被释放了 </script> 

通过上面的例子可以看出,如果某个函数中dom元素保存了内部函数的引用,就会形成闭包,很容易引起泄露,务必小心
另firefox下测试是没有这些问题的
posted @ 2009-11-19 11:52  lzwlfw  阅读(313)  评论(0编辑  收藏  举报