var n = 123; // 为数字分配内存
var s = 'azerty'; // 为String分配内存
var o = {
a: 1,
b: null
}; // 为对象分配内存
// 为数组分配内存
var a = [1, null, 'abra'];
function f(a) {
return a + 2;
} // 为函数分配内存
通过函数调用分配内存空间:
var d = new Date(); // 通过new分配date对象
var e = document.createElement('div'); // 分配一个DOM对象
var s = 'azerty';
var s2 = s.substr(0, 3); // 因为js中字符串是不可变的,所以substr的操作将会创建新的字符串
var a = ['ouais ouais', 'nan nan'];
var a2 = ['generation', 'nan nan'];
var a3 = a.concat(a2);
// 同样的,concat操作也会创建新的字符串
var x = {
a: {
b: 2
}
};
//我们创建了两个对象,a对象和a外面用大括号创建的对象。
// 我们将大括号创建的对象引用赋值给了x变量,所以x拥有大括号创建对象的引用,该对象不能够被回收。
// 同时,因为a对象是创建在大括号对象内部的,所以大括号对象默认拥有a对象的引用
// 因为两个对象都有引用,所以都不能够被垃圾回收
var y = x; //我们将x赋值给y,大括号对象现在拥有两个引用
x = 1; // 我们将1赋值给x,这样只有y引用了大括号的对象
var z = y.a; // 将y中的a对象引用赋值给z,a对象拥有两个引用
y = 'flydean'; // 重新赋值给y,大括号对象的引用数为0,大括号对象可以被回收了,但是因为其内部的a对象还有一个z在被引用
// 所以暂时不能被回收
z = null; // z引用也被重新赋值,a对象的引用数为0,两个对象都可以被回收了
引用计数的一个缺点就是可能会出现循环引用的情况。
考虑下面的一个例子:
function f() {
var x = {};
var y = {};
x.a = y; // x references y
y.a = x; // y references x
return 'flydean';
}
f();
<html>
<body>
<script type="text/javascript">
document.write("Program to illustrate memory leak via closure");
window.onload=function outerFunction(){
var obj = document.getElementById("element");
obj.onclick=function innerFunction(){
alert("Hi! I will leak");
};
obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
// This is used to make the leak significant
};
</script>
<button id="element">Click Me</button>
</body>
</html>
上面的例子中,obj引用了 DOM 对象element,而element的onclick是outerFunction的内部函数,从而导致了对外部函数的引用,从而引用了obj。
这样最终导致循环引用,造成内存泄露。
怎么解决这个问题呢?
一个简单的办法就是在使用完obj之后,将其赋值为null,从而中断循环引用的关系:
<html>
<body>
<script type="text/javascript">
document.write("Avoiding memory leak via closure by breaking the circular
reference");
window.onload=function outerFunction(){
var obj = document.getElementById("element");
obj.onclick=function innerFunction()
{
alert("Hi! I have avoided the leak");
// Some logic here
};
obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
obj = null; //This breaks the circular reference
};
</script>
<button id="element">"Click Here"</button>
</body>
</html>
还有一种很简洁的办法就是不要使用闭包,将其分成两个独立的函数:
<html>
<head>
<script type="text/javascript">
document.write("Avoid leaks by avoiding closures!");
window.onload=function()
{
var obj = document.getElementById("element");
obj.onclick = doesNotLeak;
}
function doesNotLeak()
{
//Your Logic here
alert("Hi! I have avoided the leak");
}
</script>
</head>
<body>
<button id="element">"Click Here"</button>
</body>
</html>