js垃圾回收机制

javaScript的内存分配

变量初始化

javaScript在定义变量时,就完成了内存的分配。

1
2
3
4
5
6
7
8
9
10
var n = 123; // 给数值变量分配内存
// 为对象及其包含变量分配内存
var o = {
a: 1,
b: null
};
// 函数表达式也能分配一个对象
obj.addEventListener("click", function(){
obj.style.backgroundColor = 'blue';
}, false);

通过函数调用的内存分配

有些函数调用结果是分配对象内存

1
2
var d = new Date();
var e = document.createElement('div');

值的使用

使用值的过程实际是对分配内存进行读取与写入的操作。

当内存不在需要使用时释放

利用“垃圾回收器”,主要工作是跟踪内存的分配和使用,以便当分配的内存不在使用时,自动释放它。但要知道某块内存是否需要是无法判定的。

垃圾回收机制——GC

原理:垃圾收集器会定期(周期性)找出那些不再继续使用的变量,然后释放它的内存。

不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器也在页面才会结束。局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在堆或栈上分配相应的空间,以存储它们的值,在后再函数中使用这些变量,直至函数结束,而闭包中由于内部函数的原因,外部函数并不能算是结束。

1
2
3
4
5
6
7
8
9
function fn1() {
var obj = {name: 'yu', age: 10};
}
function fn2() {
var obj = {name: 'yu', age: 11};
return obj;
}
var a = fn1();
var b = fn2();

fn1在a赋值操作后被释放,而fn2,它返回的对象被全局变量b所指向,所以该块内存并不会被释放。

怎么区别那些变量无用:

标记清除

当变量进入环境时,如:在函数中声明一个变量,就将这个变量标记为“进入环境”。当变量离开环境时,就将其标记为“离开环境”。

引用计数

最简单的垃圾收集算法。

如果没有引用指向该对象(即0引用),对象将被垃圾回收机制回收。但现在存在一个循环引用:

1
2
3
4
5
6
7
function fn() {
var a = {};
var b = {};
a.pro = b;
b.pro = a;
}
fn(); // 其中a引用b,b引用a。这样他们俩的引用次数都为2,fn执行完,他们还是不会被垃圾回收

手动解除循环引用:

1
2
fn.a = null;
a.pro = null;

内存管理

1、解决什么时候触发垃圾回收的问题:

在IE6中:根据内存分配量运行的,当环境中存在256个变量、4096个对象、64k的字符串任意一种情况是就会触发。但现在脚本复杂,一直存在这么多变量的情况很多,所以垃圾回收就会一直工作,那浏览器就没有办法处理其他任务。

在IE7中做出了调整:触发条件是动态的。初始值和IE6相同,如果垃圾回收器回收的内存分配量低于程序占用内存的 15%,说明大部分内存不可被回收,设的垃圾回收触发条件过于敏感,这时候把临界条件翻倍,如果回收的内存高于 85%,说明大部分内存早就该清理了,这时候把触发条件置回。这样就使垃圾回收工作智能了很多。

2、合理的 GC 方案
1)、JavaScript 引擎基础 GC 方案是(simple GC):mark and sweep(标记清除),即:

  • 遍历所有可访问的对象。
  • 回收已不可访问的对象。

2)、GC 的缺陷
和其他语言一样,JavaScript 的 GC 策略也无法避免一个问题:GC 时,停止响应其他操作,这是为了安全考虑。而 JavaScript 的 GC 在 100ms 甚至以上,对一般的应用还好,但对于 JS 游戏,动画连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免 GC 造成的长时间停止响应。