昨天在群里和西门,天天讨论js的内存泄露问题。

JS的内存泄露,无怪乎就是从DOM中remove了元素,但是依然有变量或者对象引用了该DOM对象。然后内存中无法删除。使得浏览器的内存占用居高不下。这种内存占用,随着浏览器的刷新,会自动释放。

而另外一种情况,就是循环引用,一个DOM对象和JS对象之间互相引用,这样造成的情况更严重一些,即使刷新,内存也不会减少。这就是严格意义上说的内存泄露了。

感谢天天,提供了IE6给我们的脚本进行测试,然后我们发现IE6的内存泄露问题确实特别严重,而我的IE8下不会出现的问题,在IE6下反而很容易出现。

首先,我写了一个制造一个大DOM对象的函数。很简单,就是给DOM对象增加了一个很大很大的属性。恩。几MB

function MemoryLeak(){

var p=document.createElement(“p”);

p.bigAttribute=new Array(1000).join(new Array(1000).join(“xxxx”));

}

一百万个XXXX,几个MB,恩

首先,一个明显的循环引用。

function MemoryLeak(){

var o={};

o.p=document.createElement(“p”);

o.p.bigAttribute=new Array(1000).join(new Array(1000).join(“xxxx”));

o.p.e=o;

}

这个肯定没问题,js对象o和DOM对象p之间形成了相互引用。

在IE6下,内存溢出了,即使刷新,内存占用也不会下降。在我的IE8下,内存不会增加。IE8改进了不少问题嘛。窃喜中。。。

西门提供了一个函数,也是会造成IE6的内存溢出。

function leak_ximen(){
var fn = function(){};
var obj = document.createElement(“div”);
obj.bigAttribute=new Array(1000).join(new Array(1000).join(“xxx”));
obj.onclick = fn;
}

这个函数的内存溢出问题很隐蔽。事实上,DOM元素通过onclick引用了一个function,而function的active object引用了变量obj,而变量obj又引用了DOM元素。于是形成了一个环形引用。IE6又一次出现了问题。。。

西门又提供了另外一个方法。避免了这个问题。

function leak_ximen3(){

var fn = function(){};

(function() {

var obj = document.createElement(“div”)

obj.bigAttribute=new Array(1000).join(new Array(1000).join(“xxx”));

obj.onclick = fn;

})();

}

fn作为一个函数,这样就无法引用到obj,不会造成内存泄露。

通过这次讨论,突然觉得IE6很可怕。因为这样的内存溢出方式,在平时的代码编写中,经常这样做了。从来没有想过可能导致的问题。而西门的解决方案,从代码编写上,这样做又不现实,真的很麻烦,为了防止这种事情,只能在remove的时候,让onclick为null,显性的切断引用链。

一声叹息:其一,所有的remove都要这么做,工作量真不是一般的大,其二,还有很多事件是通过attachEvent/addEventListener的方式添加的,而JS没有提供一种清空这种事件绑定的方式,为之奈何啊。。。