图解 Google V8 # 21 :垃圾回收(二):V8是如何优化垃圾回收器执行效率的?

简介: 图解 Google V8 # 21 :垃圾回收(二):V8是如何优化垃圾回收器执行效率的?

说明

图解 Google V8 学习笔记



全停顿(Stop-The-World)


由于 JavaScript 是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。这种行为叫做全停顿(Stop-The-World)。


全停顿的执行效果示意图:下面的 200 毫秒内无法执行其他事情,可能造成页面的卡顿 (Jank)。


08c0bade3f804b7db98be9f7adccabae.png


怎么解决垃圾回收效率?


   将一个完整的垃圾回收的任务拆分成多个小的任务,这样就消灭了单个长的垃圾回收任务;


   将标记对象、移动对象等任务转移到后台线程进行,这会大大减少主线程暂停的时间,改善页面卡顿的问题,让动画、滚动和用户交互更加流畅。



并行回收


并行回收机制:主线程在执行垃圾回收的任务时,引入多个辅助线程来并行处理,这样就会加速垃圾回收的执行速度。


48a8af06660b4513aa21f1a51988d0f6.png


V8 的副垃圾回收器所采用的就是并行策略,它在执行垃圾回收的过程中,启动了多个线程来负责新生代中的垃圾清理操作,这些线程同时将对象空间中的数据移动到空闲区域。由于数据的地址发生了改变,所以还需要同步更新引用这些对象的指针。


增量回收


老生代存放的都是一些大的对象,如 window、DOM 这种,完整执行老生代的垃圾回收,时间依然会很久。这些大的对象都是主垃圾回收器的,所以在 2011 年,V8 又引入了增量标记的方式,称之为增量式垃圾回收。


所谓增量式垃圾回收,是指垃圾收集器将标记工作分解为更小的块,并且穿插在主线程不同的任务之间执行。


增量垃圾回收示意图:


656dfb9a789d415a9905b996f1d9c333.png


实现增量执行,需要满足:


   垃圾回收可以被随时暂停和重启,暂停时需要保存当时的扫描结果,等下一波垃圾回收来了之后,才能继续启动。


   在暂停期间,被标记好的垃圾数据如果被 JavaScript 代码修改了,那么垃圾回收器需要能够正确地处理。


V8 是如何实现垃圾回收器的暂停和恢复执行的?


   黑白色标记数据(采用增量算法之前)


在执行一次完整的垃圾回收之前,垃圾回收器会将所有的数据设置为白色,用来表示这些数据还没有被标记,然后垃圾回收器在会从 GC Roots 出发,将所有能访问到的数据标记为黑色。遍历结束之后,被标记为黑色的数据就是活动数据,那些白色数据就是垃圾数据。


fa094d6631f94bb79008e93123f80e85.png


这种标记存在的问题:当你暂停了当前的垃圾回收器之后,再次恢复垃圾回收器,那么垃圾回收器就不知道从哪个位置继续开始执行。


   三色标记法


   黑色:表示这个节点被 GC Root 引用到,且该节点的子节点都已经标记完成;


   灰色:表示这个节点被 GC Root 引用到,但子节点还没被垃圾回收器标记处理,也表明目前正在处理这个节点;


   白色:表示这个节点没有被访问到,如果在本轮遍历结束时还是白色,那么这块数据就会被收回。

引入灰色标记之后,垃圾回收器就可以依据当前内存中有没有灰色节点,来判断整个标记是否完成,如果没有灰色节点了,就可以进行清理工作了。如果还有灰色标记,当下次恢复垃圾回收器时,便从灰色的节点开始继续执行。


V8 是如何处理被 JavaScript 修改标记好的垃圾数据?


例子:

window.a = Object()
window.a.b = Object()
window.a.b.c = Object()


当执行到这里,垃圾回收器标记示意图:

e2cd4cf066024427a361bdb99f4bf185.png


然后执行下面的代码

window.a.b = Object() // d



垃圾回收器标记示意图:


eb214399775c4e0d923727b78276de78.png


当垃圾回收器将某个节点标记成了黑色,然后这个黑色的节点被续上了一个白色节点,那么垃圾回收器不会再次将这个白色节点标记为黑色节点了,因为它已经走过这个路径了。


解决方案:添加约束条件——不能让黑色节点指向白色节点。


通常使用写屏障 (Write-barrier) 机制实现这个约束条件:当发生了黑色的节点引用了白色的节点,写屏障机制会强制将被引用的白色节点变成灰色的,这样就保证了黑色节点不能指向白色节点的约束条件。这个方法也被称为强三色不变性。



并发回收

所谓并发 (concurrent) 回收,是指主线程在执行 JavaScript 的过程中,辅助线程能够在后台完成执行垃圾回收的操作。


并发标记的流程示意图:


7e9c01c04e634de881483e21cf8bacd4.png


并发回收难点:


   当主线程执行 JavaScript 时,堆中的内容随时都有可能发生变化,从而使得辅助线程之前做的工作完全无效;


   主线程和辅助线程极有可能在同一时间去更改同一个对象,这就需要额外实现读写锁的一些功能。


总结


V8 的主垃圾回收器就融合了这三种机制,来实现垃圾回收。

三种策略示意图:


d224e32f989d46ac8defcc8df31d9cfe.png


  1. 在主线程执行 JavaScript,辅助线程就开始执行标记操作
  2. 标记完成之后,主线程在执行清理操作时,多个辅助线程也在执行清理操作。
  3. 清理的任务会穿插在各种 JavaScript 任务之间执行。




内存泄漏问题的定位


来自 sugar 网友:


内存泄漏问题的定位,一般是通过 chrome 的 devtool 中 memory report 来观察的,nodejs 环境中的 mem leak case 我们研究的比较多,一般通过结合 memwatch 等 c++ 扩展包把 report 文件 dump 在线上机磁盘上,然后 download 下来在本地的 chrome 浏览器 devtool 中进行复盘。比较常见的 case 是一些 js 工程师对 scope 的理解不够深,复杂的闭包里出现了隐式的引用持有却没释放。此类问题一般隐蔽性比较强,而且如果不是大厂的业务线(业务高峰产生高并发环境),往往可能压根发现不了,因为就算有 leak 内存逐渐增长到 v8 的 heap limit 后 node 进程死掉就会被 pm2/forever 等守护进程复活,这个重启只要不是非常频繁往往是业务无感的~



目录
相关文章
|
2天前
|
存储 Java 程序员
V8垃圾回收?看这篇就够了!
V8垃圾回收?看这篇就够了!
|
3天前
|
算法 Java 云计算
JVM垃圾回收的历史演进:从GC算法到垃圾回收器选择
JVM垃圾回收的历史演进:从GC算法到垃圾回收器选择
|
5天前
|
监控 数据可视化 Java
如何在Java中优化垃圾回收(GC)性能
如何在Java中优化垃圾回收(GC)性能
|
25天前
|
监控 算法 Java
Java性能优化(九)-多线程调优-垃圾回收机制优化
Java性能优化(九)-多线程调优-垃圾回收机制优化
23 0
|
2月前
|
存储 监控 算法
JVM工作原理与实战(二十七):堆的垃圾回收-G1垃圾回收器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了G1垃圾回收器、G1垃圾回收器的回收方式、G1垃圾回收器执行流程、垃圾回收器的选择等内容。
36 0
|
2月前
|
机器学习/深度学习 监控 算法
JVM工作原理与实战(二十六):堆的垃圾回收-垃圾回收器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了垃圾回收器、Serial垃圾回收器、SerialOld垃圾回收器、ParNew垃圾回收器、CMS垃圾回收器、Parallel Scavenge垃圾回收器、Parallel Old垃圾回收器等内容。
24 0
|
11月前
|
数据采集 搜索推荐 安全
如何做好英文Google优化?
答案是:做足够多的GPB外链+足够多的优质内容。 理解目标受众 为了成功地进行英文Google优化,首先要深入了解您的目标受众。 这包括他们的搜索习惯、使用的关键词,以及他们在搜索结果中期待看到的内容。 选择合适的关键词 在Google优化中,关键词研究至关重要。 确保选择的关键词与您的内容高度相关,并具有适当的搜索量。 利用专业的关键词工具来为您的英文内容找到最佳关键词。
61 0
如何做好英文Google优化?
|
2月前
|
监控 Java 编译器
优化Go语言程序中的内存使用与垃圾回收性能
【2月更文挑战第5天】本文旨在探讨如何优化Go语言程序中的内存使用和垃圾回收性能。我们将深入了解内存分配策略、垃圾回收机制,并提供一系列实用的优化技巧和建议,帮助开发者更有效地管理内存,减少垃圾回收的开销,从而提升Go程序的性能。
|
12月前
|
存储 算法 Java
JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结
G1垃圾回收流程 及 垃圾回收器 总结 简述
172 0
JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结
|
12月前
|
存储 监控 算法
优化内存利用:深入了解垃圾回收算法与回收器(二)
优化内存利用:深入了解垃圾回收算法与回收器(二)
94 0