[关闭]
@Dreamingboy 2017-09-24T08:54:25.000000Z 字数 2074 阅读 752

垃圾收集机制

JavaScript


JavaScript具有自动的垃圾收集机制,也就是说在一定的周期内,浏览器的垃圾回收机制都会进行一次扫描,然后将一些不再有用的变量和对象回收,释放内存。

常见的垃圾收集机制有下面两种:

上面这段话其实可以相对简单的概括为:只有那些存在于环境中以及能够被环境引用的变量才不会被回收

下面这张图是一张很经典的说明这个原理的图:

垃圾回收机制](![QQ图片20170924143735.jpg-63.5kB

红色的圆圈代表的是根对象,也就是在JavaScript中常说window对象。需要注意的是root是永远不会被回收的

假设现在开始执行垃圾回收,那么就会从root开始,然后遍历每个对象、函数、变量。并且依次为它们做上标记。假设现在在全局作用域中具有两个函数2和3,这样的话2和3就可以被root引用到,也就是处于环境中,然后2和3又通过别的一些方法连接到4,5,6,7,8,这样的话其实4,5,6,7,8其实都是处于这个环境之内,而9和10处于这个环境之外,因此最后只有9和10会被回收。

下面通过一个例子来看一下:

  1. function example(name){
  2. let object = {
  3. a:1,
  4. b:"name",
  5. name:name,
  6. sayName:function(){
  7. console.log(this.name);
  8. }
  9. };
  10. return object;
  11. }
  12. let object1 = example("mike");
  13. object1.sayName();
  14. let object2 = example("bob");

首先说明一点,这个函数是在全局作用域中i运行的,接下来我们一步步来说明垃圾回收的过程
首先在全局作用域中创建example函数,然后在下面调用了example创建了一个对象,返回这个对象,变量object1指向创建的对象。

假设现在垃圾开始进行垃圾回收:首先由于example这个函数是在全局作用域的,所以其与root之间存在联系,不会被回收,接下来调用了example这个函数创建了一个对象,但是由于object1这个全局变量指向这对象,那么这个对象也不会被回收。

把上面的例子稍微改变了一下,看看下面这种情况:

  1. function example(name){
  2. let object = {
  3. a:1,
  4. b:"name",
  5. name:name,
  6. sayName:function(){
  7. console.log(this.name);
  8. }
  9. };
  10. return object;
  11. }
  12. let object1 = example("mike");
  13. object1.sayName();
  14. object1 = null;
  15. example = null;
  16. let object2 = example("bob");//报错!

在中间加了两句,将object1、example设置为null之后,相当于切断了object1和对象的连接以及example和函数的连接这样的话当再次进行垃圾回收的时候example这个函数和object1指向的那个对象就会被回收。

  1. var a = { name:"bob",age:10 };
  2. var b = a;
  3. a = null;

上面这个例子中,首先创建了一个对象,然后用a这个变量去引用这个对象,这样话对象的引用次数是1,接着创建了一个新的变量b指向对象,增加了对象的引用次数,现在对象的引用次数是2,接下来将a赋值为null,对象的引用次数减少1。

但是,引用计数存在一个问题就是循环引用,看看下面这个例子:

  1. function temp1(){
  2. var temp2 = new Object();
  3. var temp3 = new Object();
  4. temp2.nextObject = temp3;
  5. temp3.nextObject = temp2;
  6. }

上面这个例子中,就算这个函数执行结束也还是两个对象的引用次数都是非零,所以这两个对像永远都不会被垃圾回收。所以这就有可能引发内存泄露

一般解决这个问题都是手动将引用设置为null。像上面这个例子其实可以通过下面这种方法来实现

  1. function temp1(){
  2. var temp2 = new Object();
  3. var temp3 = new Object();
  4. temp2.nextObject = temp3;
  5. temp3.nextObject = temp2;
  6. temp2 = null;
  7. temp3 = null;
  8. temp2.nextObject =null;
  9. temp3.nextObject =null;
  10. }

所以,现在主要的垃圾回收机制都是采用标记清除

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注