垃圾回收机制
垃圾回收概念
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程序的执行
- 将一整垃圾回收操作拆分成多个小步,组合成去完成我们当前整个回收,从而替换我们之前一口气做完的垃圾回收,让我们实现垃圾回收与程序运行交替完成,时间消耗会更加合理
