分享
 
 
 

理解并解决IE的内存泄漏方式

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

本文将讲书述losures引起的IE内存泄漏,在本文中Closures翻译成闭包或闭包函数。最近在网上看到一个对Closures的解释,它是这么说的:

<Html>

<HEAD>

<script language="javascript">

function initpage()

{

window.setTimeout("window.location.reload()", 500, "Javascript");

}

</script>

</HEAD>

<body onload="initpage()" >

<div class='menu' id='menu'></div>

<script language='javascript'>

hookup(document.getElementById('menu'));

function hookup(element)

{

element.attachEvent( "onmouSEOver", mouse);

function mouse ()

{}

}

</script>

</body>

</HTML>

In this code, the handler (the mouse function) is nested inside the attacher (the hookup function). This arrangement means that the handler is closed over the scope of the caller (this arrangement is named a "closure").

闭包函数(Closures)

由于闭包函数会使程序员在不知不觉中创建出循环引用,所以它对资源泄漏经常有着不可推卸的责任。而在闭包函数自己被释放前,我们很难判定父函数的参数以及它的局部变量是否能被释放。实际上闭包函数的使用已经很普通,以致人们频繁的碰到这类问题时我们却束手无策。在具体了解了闭包背后的问题和一些非凡的闭包泄漏示例后,我们将结合循环引用的图示找到闭包的所在,并找出这些不受欢迎的引用来至何处。

Figure 1. 闭包函数引起的循环引用

普通的循环引用,是两个不可探知的对象相互引用造成的,但是闭包却不同。代替直接造成引用,闭包函数则取而代之从其父函数作用域中引入信息。通常,函数的局部变量和参数只能在该被调函数自身的生命周期里使用。当存在闭包函数后,这些变量和参数的引用会和闭包函数一起存在,但由于闭包函数可以超越其父函数的生命周期而存在,所以父函数中的局部变量和参数也仍然能被访问。在下面的示例中,参数1将在函数调用终止时正常被释放。当我们加入了一个闭包函数后,一个额外的引用产生,并且这个引用在闭包函数释放前都不会被释放。假如你碰巧将闭包函数放入了事件之中,那么你不得不手动从那个事件中将其移出。假如你把闭包函数作为了一个eXPando属性,那么你也需要通过置null将其清除。

同时闭包会在每次调用中创建,也就是说当你调用包含闭包的函数两次,你将得到两个独立的闭包,而且每个闭包都分别拥有对参数的引用。由于这些显而易见的因素,闭包确实非常用以带来泄漏。下面的示例将展示使用闭包的主要泄漏因素:

<html>

<head>

<script language="JScript">

function AttachEvents(element)

{

// This strUCture causes element to ref ClickEventHandler

element.attachEvent("onclick", ClickEventHandler);

function ClickEventHandler()

{

// This closure refs element

}

}

function SetupLeak()

{

// The leak happens all at once

AttachEvents(document.getElementById("LeakedDiv"));

}

function BreakLeak()

{}

</script>

</head>

<body onload="SetupLeak()" onunload="BreakLeak()">

<div id="LeakedDiv"></div>

</body>

</html>

假如你对怎么避免这类泄漏感到迷惑,我将告诉你处理它并不像处理普通循环引用那么简单。"闭包"被看作函数作用域中的一个临时对象。一旦函数执行退出,你将失去对闭包本身的引用,那么你将怎样去调用detachEvent方法来清除引用呢?在Scott Isaacs的MSN Spaces上有一种解决这个问题的有趣方法。这个方法使用一个额外的引用(原文叫second closure,可是这个示例里致始致终只有一个closure)协助window对象执行onUnload事件,由于这个额外的引用和闭包的引用存在于同一个对象域中,于是我们可以借助它来释放事件引用,从而完成引用移除。为了简单起见我们将闭包的引用暂存在一个expando属性中,下面的示例将向你演示释放事件引用和清除expando属性。

<html>

<head>

<script language="JScript">

function AttachEvents(element)

{

// In order to remove this we need to put

// it somewhere. Creates another ref

element.expandoClick = ClickEventHandler;

// This structure causes element to ref ClickEventHandler

element.attachEvent("onclick", element.expandoClick);

function ClickEventHandler()

{

// This closure refs element

}

}

function SetupLeak()

{

// The leak happens all at once

AttachEvents(document.getElementById("LeakedDiv"));

}

function BreakLeak()

{

document.getElementById("LeakedDiv").detachEvent("onclick",

document.getElementById("LeakedDiv").expandoClick);

document.getElementById("LeakedDiv").expandoClick = null;

}

</script>

</head>

<body onload="SetupLeak()" onunload="BreakLeak()">

<div id="LeakedDiv"></div>

</body>

</html>

在这篇文章中,实际上建议我们除非迫不得已尽量不要创建使用闭包。文章中的示例,给我们演示了非闭包的事件引用方式,即把闭包函数放到页面的全局作用域中。当闭包函数成为普通函数后,它将不再继续其父函数的参数和局部变量,所以我们也就不用担心基于闭包的循环引用了。在非必要的时候不使用闭包这样的编程方式可以尽量使我们的代码避免这样的问题。

最后,脚本引擎开发组的Eric Lippert,给我们带来了一篇关于闭包使用通俗易懂的好文章。他的最终建议也是希望在真正必要的时候才使用闭包函数。虽然他的文章没有提及闭包会使用的真正场景,但是这儿已有的大量示例非常有助于大家起步。

不得不说Eric Lippert同志疾呼的:Don't use closures unless you really need closure semantics. In most cases, non-nested functions are the right way to go. 是非常消极的应付之辞。今天关于IE内存泄漏的文章已有很多,而且很大部分就是微软的自己人在解释,甚至象Eric Lippert这样引擎开发组的成员。但是他们的文章始终没有正面承认其实这就是IE的bug,而且是非常严重的bug,这事情其实完全不关脚本引擎对象和DOM对象的事。就是微软对产品不负责任的表现,不说IE4,1997那个春天那是太遥远了点,但是IE6也是2001年随xp发布的。使用COM可以给他们的开发带来很多便利,当然也利用很多现成的东西,可是居然在带来这样的严重问题后,他们却把大部分责任归咎于不合理和不正确的使用Closures技术!对于循环引用产生Memory Leak我根本就是不好意思提了,那样的问题是应该发生的吗?那就让我们拭目以待看IE7怎么解决这堆shit问题吧,当然我希望不要再看到类似:Do not use closures unless they are necessary. 这样的扯淡建议!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有