# 前言
所谓内存泄漏就是不再使用的内存没有及时释放。
JavaScript 具有自动垃圾回收机制(Garbage Collection)。
JavaScript 程序每次创建字符串,数组,对象时,解释器都必须分配内存来存储那个实体,只要像这样动态分配了内存,最终都要释放这些内存以便它们能够被再用,否则,JS 的解释器将会消耗完系统中的所有可用的内存,造成系统崩溃。
# 垃圾回收机制
# 标记清除
JS 中最常用的垃圾回收方式
垃圾收集器在运行时会给存储在内存中的所有变量加上标记,然后,去掉环境中的变量以及被引用的变量的标记,之后再被加上的标记的变量为准备删除的变量,最后,垃圾收集器完成内存清除工作,销毁那些带标记的变量,回收它们占用的空间。
# 引用计数
语言引擎有一张“引用表”,保存了内存中所有的资源的引用次数。如果一个值的引用次数是 0,则表示不再使用了,可以释放这块内存。
# 引起内存泄漏
# 全局变量
可以启用严格模式解析 JavaScript ,避免意外的全局变量。
# 被遗忘的计时器或回调函数
var someResource = getData();
setInterval(function () {
var node = document.getElementById('Node');
if (node) {
// 处理 node 和 someResource
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
定时器包含对 someResource 的引用,定时器外部的变量不会释放。
# 闭包
闭包可以维持函数内局部变量,使其得不到释放。
# 没有清理的 DOM 元素引用
var elements = {
button: document.getElementById('button'),
image: document.getElementById('image'),
text: document.getElementById('text')
};
function doStuff() {
image.src = 'http://some.url/image';
button.click();
console.log(text.innerHTML);
}
function removeButton() {
document.body.removeChild(document.getElementById('button'));
// 此时,仍旧存在一个全局 elements 引用了 #button
// button 元素仍旧在内存中,不能被 GC 回收。
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15