JavaScript内存泄漏Word文档下载推荐.docx
《JavaScript内存泄漏Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《JavaScript内存泄漏Word文档下载推荐.docx(9页珍藏版)》请在冰点文库上搜索。
闭包可以导致内存泄漏是因为内部方法保持一个对外部方法变量的引用,所以尽管方法返回了内部方法还可以继续访问在外部方法中定义的私有变量。
对Javascript程序员来说最好的做法是在页面重载前断开所有的事件处理器。
3)DOM插入顺序
当2个不同范围的DOM对象连添加到一起的时候一个临时的对象会被创建。
这个DOM对象改变范围到document时,那个临时对象就没用了。
也就是说,DOM对象应该按照从当前页面存在的最上面的DOM元素开始往下直到剩下的DOM元素的顺序添加,这样它们就总是有同样的范围,不会产生临时对象。
4)如何检测?
内存泄漏对开发者来说一般很难检测因为它们是由一些大量代码中的意外的错误引起的,但它在系统内存不足前并不影响程序的功能。
这就是为什么会有人在很长时间的测试期中收集应用程序性能指标来测试性能。
最简单的检测内存泄漏的方式是用任务管理器检查内存使用情况。
在Chrome浏览器的新选项卡中打开应用并查看内存使用量是不是越来越多。
还有其他的调试工具提供内存监视器,比如Chrome开发者工具。
这是谷歌开者这网站中的堆分析的特性的教程。
什么是内存泄露
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。
在C++中,因为是手动管理内存,内存泄露是经常出现的事情。
而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使用的情况下几乎不会发生内存泄露。
浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。
内存泄露QuickView
不同的浏览器中存在各种内存泄露方式,目前发现的主要是这样几种:
1.循环引用
已经确认存在泄漏的浏览器:
IE6.0FF2.0
含有DOM对象的循环引用将导致大部分当前主流浏览器内存泄露这里有两个简单的概念
引用:
a.属性=b,a就引用了b
循环引用:
简单来说假如a引用了b,b又引用了a,a和b就构成了循环引用。
a和b循环引用:
vara=newObject;
varb=newObject;
a.r=b;
b.r=a;
a循环引用自己:
vara=newObject;
a.r=a;
循环引用很常见且大部分情况下是无害的,但当参与循环引用的对象中有DOM对象或者ActiveX对象时,循环引用将导致内存泄露。
我们把例子中的任何一个newObject替换成document.getElementById或者document.createElement就会发生内存泄露了。
尽管这看起来非常容易理解,但是因为有closure的参与而使事情变得复杂,有些closure导致的循环引用很难被察觉。
下面是一个非常常见的动态绑定事件:
functionbindEvent()
{
varobj=document.createElement("
XXX"
);
obj.onclick=function(){
//Evenifit'
saemptyfunction
}
}
这个bindEvent执行时100%会发生内存泄露,Someone可能会问,哪里出现了循环引用?
关于closure和scopechain参与的循环引用比较复杂,此处暂不深入讨论。
有一个简单的判断方式:
函数将间接引用所有它能访问的对象。
obj.onclick这个函数中可以访问外部的变量obj所以他引用了obj,而obj又引用了它,因此这个事件绑定将会造成内存泄露。
在IBM的文章中介绍了2种方式解决类似的问题一个是obj=null,另一个是把onclick的函数写在bindEvent外,重复人家的我就不说了。
简单贴下代码:
obj.onclick=onclickHandler;
functiononclickHandler(){
//dosomething
obj=null;
这两个方法都打断了循环引用,可以解决问题,但是似乎对代码表达能力造成了一定破坏,假设有这么一个问题:
varvar0="
OOXX"
;
//Hereisavariable
alert(var0);
//Iwanttovisitvar2here!
returnobj;
//bindEventmustreturnobj!
好了,这下两种办法都不行了,假如我把函数写外面去,var0肯定访问不了,假如我把obj弄成null,还怎么return它呢?
这并不是空想的需要,这实际上是一个用JS定制DOM控件的简单抽象:
创建DOM元素、设置私有属性、绑定事件。
所以,我们必须update一下两个方法。
首先,方法1,为了让函数能访问某些变量,我们可以通过一个Builder函数来订制onclick的外部闭包:
obj.onclick=onclickBuilder(var0);
//想访问谁就把谁传进去!
!
functiononclickBuilder(var0)//这里跟上面对应上就行了最好参数名字也对应上
returnfunction(){
第二个办法,这个来自51js的chpn同学,让obj=null在return之后执行!
functionbindEvent()
try{
}finally{
2.某些DOM操作
这是IE系列的特有问题简单的来说就是在向不在DOM树上的DOM元素appendChild,可能会发生内存泄露(只是可能,具体原因不明,似乎十分复杂,下面例子中去掉onClick也可以避免泄露)。
所以appendChild的顺序可能影响内存泄露,来自微软的例子:
<
/html>
head>
scriptlanguage="
JScript"
>
functionLeakMemory()
{
varhostElement=document.getElementById("
hostElement"
//Doitalot,lookatTaskManagerformemoryresponse
for(i=0;
i<
5000;
i++)
varparentDiv=
document.createElement("
<
divonClick='
foo()'
"
varchildDiv=
//Thiswillleakatemporaryobject
parentDiv.appendChild(childDiv);
hostElement.appendChild(parentDiv);
hostElement.removeChild(parentDiv);
parentDiv.removeChild(childDiv);
parentDiv=null;
childDiv=null;
hostElement=null;
functionCleanMemory()
//Changingtheorderisimportant,thiswon'
tleak
/script>
/head>
body>
buttononclick="
LeakMemory()"
MemoryLeakingInsert<
/button>
CleanMemory()"
CleanInsert<
divid="
/div>
/body>
/html>
而在IE7中,貌似为了改善内存泄露,IE7采用了极端的解决方案:
离开页面时回收所有DOM树上的元素,其它一概不管。
但是这不仅没起到任何作用,反而使问题变得更加复杂。
对这类问题,除了自觉一点绕开这些恶心的东西,多用innerHTML这种无用的建议之外。
我想可以通过覆盖document.createElement来略为改善:
首先我们定义一个看不见的元素当作垃圾箱,所有新创建的元素都扔进垃圾箱里,这样保证了所有DOM元素都在DOM树上,IE7就可以正确回收了,另一方面也能避免所谓的”appendChild顺序不对导致内存泄露”。
functionMemoryFix(){
vargarbageBox=document.createElement("
div"
garbageBox.style.display="
none"
document.body.appendChild(garbageBox);
varcreateElement=document.createElement;
document.createElement=function(){
varobj=Function.prototype.apply.apply(createElement,[document,arguments]);
garbageBox.appendChild(obj);
3.自动类型装箱转换
别不相信,下面的代码在ie系列中会导致内存泄露
vars=”lalala”;
alert(s.length);
s本身是一个string而非object,它没有length属性,所以当访问length时,JS引擎会自动创建一个临时String对象封装s,而这个对象一定会泄露。
这个bug匪夷所思,所幸解决起来相当容易,记得所有值类型做.运算之前先显式转换一下:
vars="
lalala"
alert(newString(s).length);