程序员让前端飞

【js】浅析js垃圾回收机制

2017-07-24  本文已影响0人  陈小俊先生

引言:对于 C 语言这般的低级语言,一般可以通过比如 malloc() 和 free()可以在内存中释放我们定义的变量。但是JavaScript的垃圾回收是自动进行的,那么js在何时回收变量呢?


首先来看一下内存的生命周期:

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时将其释放\归还

所以,我们只要知道js引擎怎么判断内存变量不再需要,就知道js是在什么时候回收内存变量了。

我们先来说一种古老的垃圾回收机制:

引用计数垃圾收集

这是最简单的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。

我们看一段代码来分析:

// 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量o
// 很显然,没有一个可以被垃圾收集
var o = { 
  a: {
    b:2
  }
}; 

// o2变量是第二个对“这个对象”的引用
var o2 = o; 

// 现在,“这个对象”的原始引用o被o2替换了
o = 1;      

// 引用“这个对象”的a属性
// 现在,“这个对象”有两个引用了,一个是o2,一个是oa
var oa = o2.a; 

// 最初的对象现在已经是零引用了
// 他可以被垃圾回收了
// 然而它的属性a的对象还在被oa引用,所以还不能回收
o2 = "yo"; 
oa = null; 
// a属性的那个对象现在也是零引用了
// 它可以被垃圾回收了

引用计数垃圾收集有一个很大的缺陷:无法处理循环引用

比如,无法处理下列代码:

function f(){
  var o = {};
  var o2 = {};
  
  // o 引用 o2
  o.a = o2; 

  // o2 引用 o
  o2.a = o; 
}

f();

其实,引用计数垃圾收集 是古老的IE 6, 7 采用的垃圾手机机制,去他喵的IE6,7

接下来我们介绍一个更现代化的垃圾收集机制:

标记-清除垃圾收集

这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。

这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。定期的,垃圾回收器将从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象。

这个算法比前一个要好,因为“有零引用的对象”总是不可获得的,但是相反却不一定。怎么理解呢?比如这段引用计数没法回收的代码:

function f(){
  var o = {};
  var o2 = {};
  
  // o 引用 o2
  o.a = o2; 

  // o2 引用 o
  o2.a = o; 
}

f();
// 定期从window对象开始,o和o2不可获得,回收

从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。所有对JavaScript垃圾回收算法的改进都是基于标记-清除算法的改进,并没有改进标记-清除算法本身和它对“对象是否不再需要”的简化定义。

上一篇下一篇

猜你喜欢

热点阅读