21 | 垃圾回收(二):V8是如何优化垃圾回收器执行效率的?
李兵
该思维导图由 AI 生成,仅供参考
你好,我是李兵。
上节我们介绍了 V8 使用副垃圾回收器和主垃圾回收器来处理垃圾回收,这节课我们看看 V8 是如何优化垃圾回收器的执行效率的。
由于 JavaScript 是运行在主线程之上的,因此,一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。我们把这种行为叫做全停顿(Stop-The-World)。
一次完整的垃圾回收分为标记和清理两个阶段,垃圾数据标记之后,V8 会继续执行清理和整理操作,虽然主垃圾回收器和副垃圾回收器的处理方式稍微有些不同,但它们都是主线程上执行的,执行垃圾回收过程中,会暂停主线程上的其他任务,具体全停顿的执行效果如下图所示:
可以看到,执行垃圾回收时会占用主线程的时间,如果在执行垃圾回收的过程中,垃圾回收器占用主线程时间过久,就像上面图片展示的那样,花费了 200 毫秒,在这 200 毫秒内,主线程是不能做其他事情的。比如,页面正在执行一个 JavaScript 动画,因为垃圾回收器在工作,就会导致这个动画在这 200 毫秒内无法执行,造成页面的卡顿 (Jank),用户体验不佳。
为了解决全停顿而造成的用户体验的问题,V8 团队经过了很多年的努力,向现有的垃圾回收器添加并行、并发和增量等垃圾回收技术,并且也已经取得了一些成效。这些技术主要是从两方面来解决垃圾回收效率问题的:
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
V8引擎通过优化垃圾回收器的执行效率来提升性能。JavaScript运行在主线程上,因此垃圾回收算法的执行会导致脚本暂停,称为全停顿。为了解决全停顿带来的用户体验问题,V8团队引入了并行、并发和增量等垃圾回收技术。并行回收机制通过引入多个辅助线程来并行处理垃圾回收任务,加速执行速度。副垃圾回收器采用了并行策略,启动多个线程来负责新生代中的垃圾清理操作,同时更新引用这些对象的指针。这些技术的应用消除了单个长的垃圾回收任务,减少了主线程暂停的时间,改善了页面卡顿问题,使动画、滚动和用户交互更加流畅。通过这些优化,V8引擎在垃圾回收执行效率方面取得了一定成效。另外,增量式垃圾回收和并发回收机制也被引入,进一步提高了垃圾回收的效率和性能。增量式垃圾回收将标记工作分解为更小的块,并且穿插在主线程不同的任务之间执行,而并发回收则允许辅助线程在后台完成执行垃圾回收的操作,避免了主线程被挂起。这些技术的融合使得V8引擎在垃圾回收方面取得了显著的进展,为提升JavaScript执行效率和用户体验做出了重要贡献。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《图解 Google V8》,新⼈⾸单¥59
《图解 Google V8》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(14)
- 最新
- 精选
- 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等守护进程复活,这个重启只要不是非常频繁往往是业务无感的~
作者回复: 你是一线专家👍
2020-05-0299 - Shine这跟JVM的垃圾回收机制一模一样
作者回复: 类似的
2020-05-136 - HoSalt别把对象关联到全局变量上,避免循环引用
作者回复: 对
2020-05-035 - sugar另外还想请教一点,不知我的理解对不对。在nodejs这一端,结合今天的课程我们知道v8的gc是有线程优化的,那么是不是说 在线上服务器,我们如果给node提供2核心甚至更多核心的运行环境,能够使gc的stw时间更短?gc效率更高? 不知这一点我的理解对不对,如果对的话,引申出一个值得探讨的问题:我们作为线上node集群的资源利用管理角度,应该如何判定当前的node进程gc的stw时间是多长,我又该提供给它多少核心的宿主环境 能够让gc效率达到最优呢?2020-05-0216
- 锐避免没错泄露很重要一点就是避免对象的循环引用,这个很容易造成这个对象永远不会被标记而持续占用内存,同时大对象或大数组最好在使用完之后赋值为undefined释放内存~还有一点就是使用angular等框架的时候对事件的监听要在组件销毁的同时移除监听,否则这个监听的回调函数所占用内存也是不会释放的~以上是我在做项目性能优化的时候总结的一些点,应该是比较常见但又容易被忽视的吧😁2020-11-2214
- 杨阳感觉并发回收和并行回收有点不明白,并行不会阻塞主线程吧,并发会阻塞主线程。2020-10-2812
- samuel并行回收,垃圾回收所消耗的时间,等于辅助线程数量乘以单个线程所消耗的时间加同步开销,这样的话,效率还不如直接在主线程执行垃圾回收,不明白并行回收的优势在哪2020-07-1912
- sheeeeep请教一下,写屏障机制有一点没理解。文中说,当黑节点指向白节点,会把白节点变为灰节点。但是,黑节点表示自己和子节点都已经标记为引用,灰节点表示子节点还没开始标记,那黑节点指向灰节点是矛盾的吗?2020-05-0332
- 余亚勇老师我想问一下,您在文中说: 采用并行回收时,垃圾回收所消耗的时间,等于总体辅助线程所消耗的时间(辅助线程数量乘以单个线程所消耗的时间) 为什么是辅助线程时间的总和?这样的话采用并行的意义是什么?2021-09-281
- BlingBling老师您好,有一个问题想不明白,既然并发回收的方式是在辅助线程上执行的,并不会占用主线程的CPU,那么垃圾回收器为什么不直接完全使用并发回收呢?这种方式是对主线程影响最小的。 在垃圾回收的过程中,JS主线程扮演的是一个什么角色呢?垃圾回收是否一定依赖主线程呢? 希望老师帮忙解一下疑惑2020-12-1621
收起评论