图解 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 等守护进程复活,这个重启只要不是非常频繁往往是业务无感的~



目录
相关文章
|
11月前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
298 27
|
11月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
12月前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
172 5
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
211 6
|
存储 JavaScript 前端开发
JavaScript垃圾回收机制与优化
【10月更文挑战第21】JavaScript垃圾回收机制与优化
180 5
|
缓存 监控 Java
"Java垃圾回收太耗时?阿里HBase GC优化秘籍大公开,让你的应用性能飙升90%!"
【8月更文挑战第17天】阿里巴巴在HBase实践中成功将Java垃圾回收(GC)时间降低90%。通过选用G1垃圾回收器、精细调整JVM参数(如设置堆大小、目标停顿时间等)、优化代码减少内存分配(如使用对象池和缓存),并利用监控工具分析GC行为,有效缓解了高并发大数据场景下的性能瓶颈,极大提升了系统运行效率。
408 4
|
缓存 监控 算法
Java面试题:描述Java垃圾回收的基本原理,以及如何通过代码优化来协助垃圾回收器的工作
Java面试题:描述Java垃圾回收的基本原理,以及如何通过代码优化来协助垃圾回收器的工作
173 8
|
监控 算法 Java
Java中的垃圾回收机制及其优化策略
在Java编程世界中,垃圾回收(Garbage Collection, GC)是一块基石,它保证了内存管理的自动化与高效性。本文将探讨JVM的垃圾回收机制,分析其工作原理,并介绍如何通过不同的配置和实践来优化垃圾回收过程,以提升Java应用的性能。
|
并行计算 安全 算法
Java面试题:Java内存管理与多线程并发处理,设计一个Java应用,该应用需要处理大量并发用户请求,同时要求对内存使用进行优化,如何通过垃圾回收机制优化内存使用?
Java面试题:Java内存管理与多线程并发处理,设计一个Java应用,该应用需要处理大量并发用户请求,同时要求对内存使用进行优化,如何通过垃圾回收机制优化内存使用?
115 0
|
存储 Java 程序员
V8垃圾回收?看这篇就够了!
V8垃圾回收?看这篇就够了!