论坛首页 Web前端技术论坛

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

浏览 23660 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-04-14  
首先函数执行没有指明宿主情况,context是host也就是window,其实closure保存的是执行环境不是什么context,context一般情况下指函数执行过程中的this指向,应该问题就是楼上上说的从DOM无法回收,但是哪个元素的handler的closure里面还握着原来DOM的指针,也就是说浏览器刷新时候的remove和用js的remove不一样
0 请登录后投票
   发表时间:2008-04-14  
不要拿removeChild来做例子。因为这涉及另一个伪内存泄漏问题。事情要一桩一桩说,不要混在一起。
0 请登录后投票
   发表时间:2008-04-15  
看了各位高手的解释,我似乎清楚,似乎又糊涂。
那这么说,闭包还是少用的好吗?

什么情况下可以方便使用闭包呢,我是一直都在大量使用闭包的。因为很方便。
困惑。
0 请登录后投票
   发表时间:2008-04-15  
什么情况下使用闭包?什么情况下都会有闭包,只不过是你想说是不是用匿名函数直接量把你想闭的闭进去还是不闭进去
0 请登录后投票
   发表时间:2008-04-15  
我从来不让循环链发生,所以这种问题还是可以避免的
0 请登录后投票
   发表时间:2008-04-16  
oznyang 写道
在ie的内存泄露中跨页面的泄露是最严重的,浏览器刷新了仍然无法释放掉泄露占用的资源,造成访问速度越来越慢,内存占用越来越大
closure引起cross page leak的主要原因是closure和dom元素的互相引用
看这个例子:
<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树中的节点不会强行释放,所以造成了跨页面泄露,这是我的个人推测,有别的意见欢迎讨论
怎么解决这个问题呢,其实我们只要打断引用链就行了
<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>

或者
<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
<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下测试是没有这些问题的


0 请登录后投票
   发表时间:2008-06-24  
这个例子是不是就是说IE会强制释放可以访问的dom元素的资源
而divA.parentNode.removeChild(divA); 将divA这个所引用的div隐藏了,或者说设置为不可访问了,这个时候闭包里面引用的divA这个资源无法被释放,最终导致了内存泄漏??
0 请登录后投票
   发表时间:2008-06-25  
IE7疯了 没什么说的了
建议大家别试图处理IE7的内存泄露
0 请登录后投票
   发表时间:2008-06-25  
这属于IE的问题,关js鸟事。
0 请登录后投票
   发表时间:2008-07-07  
这么说遇到 IE 局部变量还是最后设 NULL比较安区
0 请登录后投票
论坛首页 Web前端技术版

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