JavaScript——垃圾收集机制

Javascript为了避免内存占用问题,提供了两种策略:第一种是标记清除,第二种是引用计数。

1.标记清除(最常用的方法)

原理:当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。当变量离开环境时,则将其标记为“离开环境”

执行方式:垃圾收集器在运行时给存储在内存中的所有变量都加上标记,然后,它会去掉环境中的变量,以及被环境中变量引用的变量的标记。而之后被标记的变量将被视为为准备删除的变量,原因是环境中的变量已经不需要再去访问到这些变量了,它们没有用处了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占的内存空间。

2.引用计数(较少用的方法)

引用计数的作用就是跟踪每个值被引用的次数。当声明了一个变量并将引用类型值赋给它的时候,则这个值引用次数就为1,如果同一个值又被赋给另一个变量,则引用次数加1.反之,如果引用这个值的变量又取得了另一个值,则这个值引用次数减1

当这个值引用次数为0时,说明无法再访问这个值了,因而就可以将其内存空间收回来。

引用计数使用次数较少的原因是循环引用会导致内存严重泄漏。

举个例子:

function problem(){

  var object1 = new Object();

  var object2 = new Object();

  object1.some = object2;

  object2.another = object1;

}

如上述,两个对象通过属性互相引用,则两个对象引用次数都是2;在采用标记清除策略的实现中,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用没有问题。但在采用引用计数策略的实现中,当函数执行完毕之后,object1和object2还将继续存在,因为它们的引用次数永远不会是0,因此会造成大量内存的浪费。

为了避免这种循环引用耗费大量内存,可以手动断开对象间的相互引用,即

object1.some = null;

object2.another = null;

将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收它们占用的内存。

上面的操作叫做“解除引用”。

要知道,为了防止运行javascript的网页耗尽全部系统内存而导致系统崩溃,分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少。web浏览器的内存被限制,这不仅会影响给变量分配内存,也会影响调用栈以及在一个线程中能够同时执行的语句数量。

因此,我们需要确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式是:为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用,这种做法叫解除引用(dereferencing)。这一做法适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时自动被解除引用。也就是说,全局变量和全局对象基本上有手动解除引用,局部变量会自动解除(这和局部变量的作用域有关)。

但是有一点这里需要特别注意,解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收(当该值不被引用的时候,就要被回收了)。

其实,垃圾回收机制特别好理解,数据不被使用的时候就成了垃圾,就该回收了。只需要确认这些东西是否被用着,如果没有人用它,那就回收咯。要是被用着,那就不回收咯。

注:在IE中,调用window.CollectGarbage()方法会立即执行垃圾收集。

总结:“标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存;另一种垃圾收集算法是“引用计数”,这种算法的思想是跟踪记录所有值被引用的次数,但是当代码中存在循环引用现象时,“引用计数”算法会导致问题。由此可见,解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处为了确保有效地回收内存,我们应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。毕竟,垃圾堆着积攒多了,就没有其它东西的立足之地了。
 

 

好啦,以上就是JavaScript中的垃圾回收机制,如果大家有疑问或者觉得文中有写的不恰当的地方,欢迎留言评论呀,我们一起学习呀!

你可能感兴趣的:(JavaScript,JavaScript,垃圾收集机制,标记清除,解除引用,引用计数)