图解 Google V8 笔记
20 | 垃圾回收(一):V8的两个垃圾回收器是如何工作的?
- JavaScript 是一门自动垃圾回收的语言
- 垃圾数据是怎么产生的?
window.test = new Object() window.test.a = new Uint16Array(100) // 产生垃圾数据 window.test.a = new Object()
- 垃圾回收算法
- 第一步,通过 GC Root 标记空间中活动对象和非活动对象
- 可访问性(reachability)算法
- 浏览器环境中,GC Root
- 全局的 window 对象(位于每个 iframe 中);
- 文档 DOM 树,由可以通过遍历文档到达的所有原生 DOM 节点组成;
- 存放栈上变量。
- 第二步,回收非活动对象所占据的内存。
- 第三步,做内存整理。
- 主垃圾回收器:产生内存碎片
- 副垃圾回收器:不产生内存碎片
- 第一步,通过 GC Root 标记空间中活动对象和非活动对象
- 代际假说(The Generational Hypothesis)
- 朝生夕死
- 函数内部声明的变量
- 块级作用域中的变量
- …
- 老不死
- 全局的 window
- DOM
- Web API
- …
- 新生代(1-8M)、老生代()
- 朝生夕死
- 副垃圾回收器 -Minor GC (Scavenger),主要负责新生代的垃圾回收。
- Scavenge 算法
- 区域划分:
- 回收过程:
- 不可到达的标记垃圾数据
- 存活对象复制到空闲区域中,同时它还会把这些对象有序地排列起来
- 角色翻转
- 区域划分:
- 为了执行效率,一般新生区的空间会被设置得比较小。
- 对象晋升策略:两次垃圾回收依然还存活的对象到老生代中
- Scavenge 算法
- 主垃圾回收器 -Major GC,主要负责老生代的垃圾回收。
- 分配到老生代中:对象晋升、大对象
- 对象特点:占用空间大、存活时间长
- 为什么不继续用 Scavenge 算法?
- 时间上:复制这些大的对象将会花费比较多的时间
- 空间上:浪费一半的空间
- 标记 – 清除(Mark-Sweep)的算法
- 标记过程
- 清除过程
- 标记 – 整理(Mark-Compact)
- 标记过程
- 清除过程
- 整理:所有存活的对象都向一端移动
21 | 垃圾回收(二):V8是如何优化垃圾回收器执行效率的?
- 全停顿(Stop-The-World)
-
垃圾回收器添加并行、并发和增量等垃圾回收技术
- 思路:
- 将一个完整的垃圾回收的任务拆分成多个小的任务
- 将标记对象、移动对象等任务转移到后台线程进行
- 思路:
- 并行回收:引入多个辅助线程来并行处理
- 仍然是全停顿
- 增量回收(增量标记):多次标记垃圾数据
- 要求:
- 垃圾回收可以被随时暂停和重启,暂停时需要保存当时的扫描结果,等下一波垃圾回收来了之后,才能继续启动。
- 在暂停期间,被标记好的垃圾数据如果被 JavaScript 代码修改了,那么垃圾回收器需要能够正确地处理。
- 要求: