垃圾回收机制

201 阅读4分钟

垃圾回收概念

JavaScript中的垃圾回收

  • JavaScript中内存管理是自动的
  • 对象不再被引用时是垃圾对象
  • 不能从根上访问到时是垃圾JavaScript中的垃圾回收

JavaScript中的可达对象

  • 可以访问到的对象就是可达对象(引用,作用域链)
  • 科大的标准就是从根出发是否能够被找到
  • JavaScript中的根就可以理解为是全局变量对象

引用计数

  • 核心思想:设置引用数,判断当前引用数是否为0
  • 引用计数器
  • 引用关系改变时修改引用数字
  • 引用数字为0时立即回收

优点

  • 发现垃圾时立即回收
  • 最大限度减少程序暂停

缺点

  • 无法回收循环引用的对象
  • 时间开销大

标记清除

  • 核心思想:分标记和清标记二哥阶段完成
  • 遍历所有对象,找到活动对象并打上标记
  • 遍历所有对象,清除没有标记的对象,并把之前打上标记的对象去掉标记
  • 回收相应的空间(把回收的空间直接当前放在我们叫做空闲列表上面,方便后面的程序可以直接申请使用)

优点

  • 相对于引用计数来说,我们可以解决循环引用不能回收的问题

缺点

  • 产生空间碎片化问题,不能让空间得到最大化的使用(空间碎片化:由于我们当前回收的垃圾对象在地址上是不连续的,由于这种不连续,造成我们回收之后,他们分散在这个角落)
  • 不会立即回收垃圾对象

标记整理

  • 标记整理可以看做是标记清除的增强
  • 标记阶段操作和标记清除一致
  • 清除阶段会先执行整理,移动对象位置

优点

  • 减少空间碎片化,把活动对象进行移动,在地址上变成连续的位置,紧接着将当前活动对象右侧范围进行整体回收,不会出现大批量分散的小空间(空间碎片)



缺点

  • 不会立即回收垃圾对象

V8垃圾回收

认识V8

  • V8是一款主流的JavaScript执行引擎
  • V8采用即时编译(之前很多JavaScript引擎都需要将我们的源代码转换成字节码,然后再去执行,v8将源码翻译成我们当前可以直接执行的机器码,速度快)
  • V8内存设限(64位不超过1.5G,32位不超过800M)

V8垃圾回收策略

  • 采用分代回收的思想
  • 内存分为新生代,老生代
  • 针对不同的对象采用不同的算法

V8常用GC算法

  • 分代回收
  • 空间复制
  • 标记清除
  • 标记整理
  • 标记增量

V8内存分配

  • V8内存空间一分为二
  • 小空间用于存储新生代对象(64位32M,32位16M)
  • 新生代指的是活动时间较短的对象

新生代对象回收实现

  • 回收过程采用复制算法+标记整理
  • 新生代内存区分为两个等大小空间
  • 使用空间为From,空闲空间为To
  • 活动对象存储于From空间
  • 标记整理后将活动对象拷贝至To
  • From与To交换空间完成释放

回收细节说明

  • 拷贝过程中可能出现晋升
  • 晋升就是将新生代对象移动至老生代
  • 一轮GC还存活的新生代需要晋升
  • To空间使用率超过25%

老生代对象说明

  • 老生代对象存放在右侧老生代区域
  • 64位操作系统1.4G,32位操作系统700M
  • 老生代对象就是指存活时间较长的对象(全局对象,闭包等)

老生代对象回收实现

  • 主要采用标记清除,标记整理,增量标记算法
  • 首先采用标记清除完成垃圾空间回收
  • 采用标记整理进行空间优化(新生代对象往老生代存储区域移动(晋升)出现空间不足,就会进行标记整理的工作)
  • 采用增量标记进行效率优化

细节对比

  • 新生代区域垃圾回收使用空间换时间
  • 老生代区域垃圾回收不适合赋值算法(1.老生代空间比较大,将区域一分为二,几百兆空间是浪费不用的。2.老生代区域存放的对象数据比较多,在复制过程中我们消耗的时间就非常多)

增量标记如何优化垃圾回收

  • 垃圾回收进行工作的时候,它其实阻塞javascript程序的执行
  • 将一整垃圾回收操作拆分成多个小步,组合成去完成我们当前整个回收,从而替换我们之前一口气做完的垃圾回收,让我们实现垃圾回收与程序运行交替完成,时间消耗会更加合理