深入理解JS垃圾回收

  

<强>前言
  

  

JS之记忆,记忆的原理是以参数作为关键,函数结果作为价值,用对象进行缓存起来,以内存空间换CPU执行事件.memoization的潜在陷阱即是严格意义的缓存有着完善的过期策略,而普通对象的键值对并没有。
  

  

用闭包进行缓存的对象的内存空间,不会在函数执行完后被清除,在执行量大和参数多样性的情况下,会造成内存占用且得不到释放。
  

  

于是,本篇文章就来讲讲JS的垃圾回收。
  

  

JS的垃圾回收机制的基本原理是:

  
  

找出那些不再继续使用的变量,然后释放其占用的内存,垃圾收集器会按照固定的时间间隔周期性地执行这一操作。

     

那我们怎么知道变量是不是在继续使用呢& # 63;
  

  

首先,局部变量的生存周期是在函数声明和执行阶段,函数执行完毕后,局部变量就没有存在的必要了。全局变量会在浏览器关闭或进程关闭才能释放。
  

  

但还有一些场景,比如闭包,通过作用域链访问到函数外部的自由变量,使得自由变量保存在内存中,不会随着函数执行完毕而结束,以及对象的相互引用等,垃圾收集器就没这么容易判断哪个变量有用,哪个变量没用了。

     //经典闭包   函数闭包(){   var name=癷nnerName”;   返回函数(){   console.log(名称);   }   }   内心var=关闭();   内部();//innerName;   之前      

所以,对于标识无用的变量的策略可能会实现不同,但目前在浏览器中,通常有两种策略:标记清除和引用计数。
  

  

<强>二、标记——清除(标记-清除)
  

  

从2012年起,所有现代浏览器都使用了标记——清除垃圾回收算法,那什么叫标记——清除呢?
  

  

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

  

垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。
  

  

然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。
  

  

最后,垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
  

  

另外,标记——清除有一个问题,就是在清除之后,内存空间是不连续的,即出现了内存碎片。如果后面需要一个比较大的连续的内存空间时,那将不能满足要求。而标记——整理(标记-整理)方法可以有效地解决这个问题。标记阶段没有什么不同,只是标记结束后,标记——整理方法会将活着的对象向内存的一端移动,最后清理掉边界的内存。
  

  

<强>三,引用计数
  

  

另外一种不太常见的垃圾收集策略叫引用计数(引用计数),此算法把“对象是否不再需要“简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
  引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的内存。
  而引用计数的不继续被使用,是因为循环引用的问题会引发内存泄漏。
  

        函数问题(){   var objA=新对象();   var objB=新对象();   objA。someObject=objB;   objB。anotherObject=objA;   }      

objA和objB通过各自的属性相互引用,也就是说,两个对象的引用次数都是2。在函数执行完毕后,objA, objB还将继续存在,因为他们的引用计数永远不会是0。假如这个函数被多次执行,就会导致大量的内存得不到释放。
  

  

<强>四,NodeJs V8中的垃圾回收机制
  

  

在节点中,通过JS使用内存时就会发现只能使用部分内存(64位系统下约为1.4 GB, 32位系统下约为0.7 GB),这导致节点无法直接操作大内存对象。

深入理解JS垃圾回收