Javascript的垃圾回收机制

1. 概述

JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。

2. 变量的生命周期

当一个变量的生命周期结束之后它所指向的内存就应该被释放。JS有两种变量,全局变量和在函数中产生的局部变量。局部变量的生命周期在函数执行过后就结束了,此时便可将它引用的内存释放(即垃圾回收),但全局变量生命周期会持续到浏览器关闭页面。

3. JS垃圾回收方式

标记清除

标记清除分为:标记阶段清除阶段
首先它会遍历堆内存上所有的对象,分别给它们打上标记,然后在代码执行过程结束之后,对所使用过的变量取消标记。在清除阶段再把具有标记的内存对象进行整体清除,从而释放内存空间。
整个标记清除算法大致过程就像下面这样:

  • 垃圾收集器在运行时会给内存中的所有变量都加上一个标记
  • 然后从各个根对象开始遍历,把还在被上下文变量引用的变量标记去掉标记
  • 清理所有带有标牌机的变量,销毁并回收它们所占用的内存空间
  • 最后垃圾回收程序做一次内存清理

使用标记清除策略的最重要的优点在于简单,无非是标记和不标记的差异。通过标记清除之后,剩余的对象内存位置是不变的,也会导致空闲内存空间是不连续的,这就造成出现内存碎片的问题。内存碎片多了后,如果要存储一个新的需要占据较大内存空间的对象,就会造成影响。对于通过标记清除产生的内存碎片,还是需要通过标记整理策略进行解决。
标记清除法的优点就是实现简单。
它的缺点有两个,首先是内存碎片化。这是因为清理掉垃圾之后,未被清除的对象内存位置是不变的,而被清除掉的内存穿插在未被清除的对象中,导致了内存碎片化。
第二个缺点是内存分配速度慢。由于空闲内存不是一整块,假设新对象需要的内存是size,那么需要对空闲内存进行一次单向遍历,找出大于等于size的内存才能为其分配。

引用计数

引用计数是一种不常见的垃圾回收策略,其思路就是对每个值都记录其的引用次数。具体的:

  • 当变量进行声明并赋值后,值的引用数为1。
  • 当同一个值被赋值给另一个变量时,引用数+1
  • 当保存该值引用的变量被其它值覆盖时,引用数-1
  • 当该值的引用数为0时,表示无法再访问该值了,此时就可以放心地将其清除并回收内存。
let a = new Object()    // 此对象的引用计数为 1(a引用)
let b = a       // 此对象的引用计数是 2(a,b引用)
a = null        // 此对象的引用计数为 1(b引用)
b = null        // 此对象的引用计数为 0(无引用)
...         // GC 回收此对象

引用计数法的优点是可以实现立即进行垃圾回收。当引用计数在引用值为0时,立即进行垃圾回收,这样可以达到立刻垃圾回收的效果。
它的缺点也有两个,首先它需要一个计数器,这个计数器可能要占据很大的位置,因为我们无法知道被引用数量的多少。
第二个缺点是无法解决当出现循环引用时无法回收的问题。例如a引用了b,b也引用了a,两个对象相互引用,引用计数不为0,因此无法进行内存清理

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容