针对 v8 引擎浅谈垃圾回收

284 阅读3分钟

1 定义

有些数据使用后,可能不再需要,这种数据称为垃圾数据。 对垃圾数据进行回收,以释放有限的内存空间,称为垃圾回收。

2 类别

手动回收:何时分配、何时销毁内存都是由代码控制(c、c++) 自动回收:产生的垃圾是由垃圾回收器来释放,并不需要手动通过代码释放

3 调用栈中的数据如何回收

有一个记录当前执行状态的指针(称为ESP),指向调用栈中当前正在执行代码的上下文,执行完成后,JavaScript会将ESP下移到另一个执行上下文,这个下移的过程就是销毁只想上下文的过程。

4 堆中的数据如何回收

回收堆中数据需要用到JavaScript的垃圾回收器。 代际假说:两个特点,第一个是很多对象一经分配内存,很快变得不可访问;第二个是不死对象,会活得更久。

4.1 以chrome中的v8引擎为例分析:

v8 中会把堆分为: 新生代:存放生存时间短的对象(1~8M) —— 使用副垃圾回收器
老生代:存放生存时间长的对象 —— 使用主垃圾回收器

垃圾回收器的流程:

  • 标记空间中的活动对象和非活动对象
  • 回收非活动对象所占据的内存
  • 内存整理(频繁回收后存在的大量不连续空间,称为内存碎片)

4.1.1 副垃圾回收器

用Scavenge算法:将新生代空间对半分为两个区域,一半是对象空间,一半是空闲区域。首先对对象区域中的垃圾做标记,副垃圾回收器会将存活的对象复制到空闲区域,并进行有序排列。完成后,进行对象区域和空闲区域角色翻转,这样就完成了垃圾对象的回收操作。

对象晋升策略:
经过两次垃圾回收依然还存活的对象,会被移到老生区。

4.1.2 主垃圾回收器:

老生区中的对象:占用空间大、对象存活时间长
采用 标记-清除 算法:
标记过程阶段:从一组根元素开始,递归遍历根元素,可到达为活动对象,否则为垃圾数据 垃圾清除:清除垃圾数据,然后使用 标记-整理算法,让所有存活对象向一端移动,然乎直接清理掉端边界以外的内存

5 全停顿

JavaScript运行在主线程上,一旦执行垃圾回收算法会将其他正在执行的js脚本暂停,待垃圾回收完毕再恢复。这种行为,称为全停顿。 此时,使用增量标记法,V8将标记过程分为一个个的子标记过程,同时让垃圾回收标记和JavaScript应用逻辑交替进行,直到标记阶段完成。由此,可将完成的垃圾回收任务分为许多小的任务,在其他js任务中间穿插执行,避免用户感受到页面卡顿。

1. 如何进行标记 2. 各算法得缺陷 3. 循环引用的问题