http://blog.thinkjs.net/archives/151
写Js的时候很多童鞋喜欢用闭包,其实闭包是非常危险的。我们先来看一个例子
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<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.test=
function
(){};
divA.parentNode.removeChild(divA);
}
leakTest();
</script>
|
在IE下这个页面每次刷新都会产生跨页面泄露,内存占用每次增大了7MB!
在这个例子中我们在leakTest()中创建了一个内部匿名函数并在dom元素aa的自定义属性test中保存了他的引用,这就产生了一个闭包。
divA.parentNode.removeChild(divA);
这句是产生泄露的主要原因,移除了aa只不过是在dom树上将这个节点移出了,在闭包中的divA这个局部变量不会被释放,而divA中保存着aa的引用,这就形成了一个循环引用,闭包保存了dom元素aa的引用,dom元素aa的自定义属性test又保存了闭包内部的匿名函数的引用,所以在页面刷新的时候IE无法释放掉这个aa和闭包的资源,在我这个例子中就比较吓人,刷一下涨几MB内存
那么如何解决这个问题呢?其实很简单只要我们打断divA 与aa的连接就可以了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<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.test=
function
(){};
divA.parentNode.removeChild(divA);
divA =
null
// fix memory leak
}
leakTest();
</script>
|
建议大家不要随意使用getElementById 这些原生的方法,最好使用jQuery object去操作dom 或存储dom,这样能减少因个人疏忽引起的内存泄漏。
毕竟内存泄漏对产品来说是非常严重的问题。