在JS中,我们创建变量、函数等都会消耗内存,如果不及时回收一些不会需要的内存,那么就会造成内存泄漏。所以我们需要对不再需要的内存进行回收,即垃圾回收。
但是如何定义垃圾,就造成不同的垃圾回收机制。
JS有自己的垃圾回收机制。以下介绍两种。
引用计数(现代浏览器不再使用)
是否被引用
var o = {
a: {
b:2
}
};
此时啊a b都被引用了,不会被回收。

function f(){
var o = {};
var o2 = {};
o.a = o2; // o 引用 o2
o2.a = o; // o2 引用 o
return "azerty";
}
f();
标记-清除算法
是否能获得
垃圾回收器从ROOT(在JS中是全局对象)开始查找,能够查找到的都添加标记,标记结束后,对所有内存进行查找,遇到没有标记的就进行回收,回收结束后,清空所有的标记,为下一轮标记-清除做准备。
这种算法也解决了引用计数中的循环引用的问题。
内存泄漏
一般来说,浏览器周期短,内存进行刷新操作或者关闭操作内存都会被释放,不容易导致内存泄漏。
但是在某些高频的操作中,不断的创建却又不进行回收就会导致内存泄漏。
或者是在nodejs搭建的网站,有些操作不当,导致内存随着时间慢慢增大而导致内存泄漏。
四种内存泄漏的场景
全局变量
function foo(arg) {
bar = "this is a hidden global variable";
}
计时器
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
// 处理 node 和 someResource
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);
回调函数
var element = document.getElementById('button');
function onClick(event) {
element.innerHTML = 'text';
}
element.addEventListener('click', onClick);
闭包
var theThing = null;
var replaceThing = function () {
var originalThing = theThing;
var unused = function () {
if (originalThing)
console.log("hi");
};
theThing = {
longStr: new Array(1000000).join('*'),
someMethod: function () {
console.log(someMessage);
}
};
};
setInterval(replaceThing, 1000);
DOM的引用
var elements = {
button: document.getElementById('button'),
image: document.getElementById('image'),
text: document.getElementById('text')
};
function removeButton() {
document.body.removeChild(document.getElementById('button'));
// 即使此处remove了button节点
// 但是仍旧存在一个全局的 #button 的引用
// elements 字典。button 元素仍旧在内存中,不能被 GC 回收。
}