内存管理
C 语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。而 JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。
整个过程为:分配内存 -> 使用内存 -> 清理内存。
JavaScript 在定义变量或者函数调用时就完成了内存分配:
var n = 123; // 给数值变量分配内存var o = {a: 1,b: null,
}; // 给对象及其包含的值分配内存// 给数组及其包含的值分配内存(就像对象一样)
var a = [1, null, "abra"];function f(a) {return a + 2;
} // 给函数(可调用的对象)分配内存// 函数表达式也能分配一个对象
someElement.addEventListener("click",function () {someElement.style.backgroundColor = "blue";},false,
);var d = new Date(); // 分配一个 Date 对象var e = document.createElement("div"); // 分配一个 DOM 元素
垃圾回收机制
1. 引用计数
var o = {a: {b: 2,},
};
// 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量 o
// 很显然,没有一个可以被垃圾收集var o2 = o; // o2 变量是第二个对“这个对象”的引用o = 1; // 现在,“这个对象”只有一个 o2 变量的引用了,“这个对象”的原始引用 o 已经没有var oa = o2.a; // 引用“这个对象”的 a 属性
// 现在,“这个对象”有两个引用了,一个是 o2,一个是 oao2 = "yo"; // 虽然最初的对象现在已经是零引用了,可以被垃圾回收了
// 但是它的属性 a 的对象还在被 oa 引用,所以还不能回收oa = null; // a 属性的那个对象现在也是零引用了
// 它可以被垃圾回收了
存在的问题:循环引用
引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。
function f() {var o = {};var o2 = {};o.a = o2; // o 引用 o2o2.a = o; // o2 引用 oreturn "azerty";
}f();
2. 标记清除
过程分为:标记 -> 清除。
首先,遍历根(root)上的所有对象,给他们打上标记。然后在代码执行结束后,对从根开始使用过(引用过)的变量取消标记,清除掉具有标记的内存对象,释放内存。