日期:2014-05-16  浏览次数:20338 次

【转】JavaScript 内存泄露

Javascript的内存泄漏,不是太可怕。它只会悄悄的,慢慢的把你的浏览器拖的巨慢无比,让你愤怒的拍案而起,大骂微软出品的破烂浏览器危害社会。这一切有可能并不是浏览器的错,可能只是因为网页 上有些javascript 的内存泄漏罢了。
在科技日益发达今天,我们有必要武装自己,以及自己的浏览器,这样万一浏览器倒下了,还能知道到底是死在谁家的网页上面。下面这个Firefox插件是推荐给那些UI设计者或者开发 人员的:Leak Monitor


This extension pops up an alert dialog to warn chromeand extension developers about one particular type of leak. It warnswhen chrome windows close but leave other code pointing at theirJavaScript objects.


Works with:
? ?? ??? Firefox? ?? ?? ?1.5 – 3.0? ?? ?? ?ALL
? ?? ??? Thunderbird? ?? ?? ?1.5 – 3.0? ?? ?? ?ALL
在你访问一张网页的时候,如果有javascript内存泄漏,这个extension就会啪的一下给你弹出一张内存泄漏的清单。就拿现在用的 wordpress后台来说吧,Leak Monitor也是毫不客气的给弹了一个窗口,主要是因为使用了大名鼎鼎的prototype.js…下载
https://addons.mozilla.org/firefox/2490/

今天下午同事让帮忙看web内存泄露问题。当时定位到创建ActiveX 对象的时候产生的,于是我对这个奇怪的问题进行了一些深入探索。

很多时候我都依赖javascript的垃圾回收机制,所以对C 以及C++ 操作内存语言常发生的内存泄露是很陌生的。当时创建回调函数用了闭包,当然最终的解决方法是也避免闭包调用。

?

? ? 随着这个问题的浮出水面,我回忆起以前的一个项目中也应该存在这个内存泄露问题。于是查阅了相关资料把类似的问题总结下来,希望对大家也有帮助。


原因:对于一门具有垃圾收回机制的语言存在内存泄露,其原因不外乎就是javascript脚本引擎存在bug。


很多时候,我们要做的不是去修正那样的bug,而是想办法去规避。

目前发现的可能导致内存泄露的代码 有三种:

· 循环引用

· 自动类型装箱转换

· 某些DOM操作

下面具体的来说说内存是如何泄露的

循环引用:这种方式存在于IE6和FF2中(FF3未做测试),当出现了一个含有DOM对象的循环引用时,就会发生内存泄露。

什 么是循环引用?首先搞清楚什么是引用,一个对象A的属性被赋值为另一个对象B时,则可以称A引用了B。假如B也引用了A,那么A和B之间构成了循环引用。 同样道理 如果能找到A引用B B引用C C又引用A这样一组饮用关系,那么这三个对象构成了循环引用。当一个对象引用自己时,它自己形成了循环引用。注意,在js中变量永远是对象的属性,它可以 指向对象,但决不是对象本身。

循环引用很常见,而且通常是无害的,但如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。例子:

var a=document.createElement("div");
var b=new Object();
a.b=b;
b.a=a;

很多情况下循环引用不是这样的明显,下面就是著名的闭包(closure)造成内存泄露的例子,每执行一次函数A()都会产生内存泄露。试试看,根据前面讲的scope对象的知识,能不能找出循环引用?

function A()...{
? ? var a=document.createElement("div");
? ? a.onclick=function()...{
? ?? ???alert("hi");
? ? }
}
A();

OK, 让我们来看看。假设A()执行时创建的作用域对象叫做ScopeA 找到以下引用关系
ScopeA引用DOM对象document.createElement("div");
DOM对象document.createElement("div");引用函数function(){alert("hi")}
函数function(){alert("hi")}引用ScopeA

这样就很清楚了,所谓closure泄露,只不过是几个js特殊对象的循环引用而已。

自动类型装箱转换:这种泄露存在于ie6 ie7中。这是极其匪夷所思的一个bug,看下面代码

var s="lalalalala";
alert(s.length);

这 段代码怎么了?看看吧,"lalalalala"已经泄露了。关键问题出在s.length上,我们知道js的类型中,string并非对象,但可以对它 使用.运算符,为什么呢?因为js的默认类型转换机制,允许js在遇到.运算符时自动将string转换为obj