图解 Google V8
李兵
前盛大创新院高级研究员
26763 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 25 讲
图解 Google V8
15
15
1.0x
00:00/00:00
登录|注册

20 | 垃圾回收(一):V8的两个垃圾回收器是如何工作的?

优化代码的角度
V8的回收过程
产生的垃圾数据
标记-整理算法
标记-清除算法
老生代的垃圾回收
对象晋升策略
Scavenge算法
新生代的垃圾回收
两个垃圾回收器
堆分为新生代和老生代
代际假说
内存整理
垃圾清理
可访问性算法
GC Root标记
内存布局示例
数据存放到栈和堆中
思考题
主垃圾回收器
副垃圾回收器
V8的垃圾回收策略
垃圾回收算法
垃圾数据产生
垃圾回收

该思维导图由 AI 生成,仅供参考

你好,我是李兵。
我们都知道,JavaScript 是一门自动垃圾回收的语言,也就是说,我们不需要去手动回收垃圾数据,这一切都交给 V8 的垃圾回收器来完成。V8 为了更高效地回收垃圾,引入了两个垃圾回收器,它们分别针对着不同的场景。
那这两个回收器究竟是如何工作的呢,这节课我们就来分析这个问题。

垃圾数据是怎么产生的?

首先,我们看看垃圾数据是怎么产生的。
无论是使用什么语言,我们都会频繁地使用数据,这些数据会被存放到栈和堆中,通常的方式是在内存中创建一块空间,使用这块空间,在不需要的时候回收这块空间。
比如下面这样一句代码:
window.test = new Object()
window.test.a = new Uint16Array(100)
当 JavaScript 执行这段代码的时候,会先为 window 对象添加一个 test 属性,并在堆中创建了一个空对象,并将该对象的地址指向了 window.test 属性。随后又创建一个大小为 100 的数组,并将属性地址指向了 test.a 的属性值。此时的内存布局图如下所示:
我们可以看到,栈中保存了指向 window 对象的指针,通过栈中 window 的地址,我们可以到达 window 对象,通过 window 对象可以到达 test 对象,通过 test 对象还可以到达 a 对象。
如果此时,我将另外一个对象赋给了 a 属性,代码如下所示:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

V8引擎的垃圾回收器是JavaScript自动垃圾回收的关键。文章介绍了垃圾数据的产生和V8引擎采用的两个垃圾回收器:副垃圾回收器-Minor GC (Scavenger)和主垃圾回收器-Major GC。副垃圾回收器主要负责新生代的垃圾回收,采用Scavenge算法。而主垃圾回收器则负责老生代中的垃圾回收,采用标记-清除(Mark-Sweep)和标记-整理(Mark-Compact)算法。V8引擎的垃圾回收策略建立在代际假说的基础上,根据对象生存周期的不同采用不同的算法,以达到最佳效果。文章还提出了一个代码示例,并邀请读者思考V8执行该代码时产生的垃圾数据以及如何优化代码。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《图解 Google V8》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(28)

  • 最新
  • 精选
  • sugar
    置顶
    分享一篇好几年前我刚开始研读v8源码时,参考的GC相关资料:https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/ 还有这个github仓库:https://github.com/yjhjstz/deep-into-node 如今与老师的这篇

    作者回复: 赞

    2020-04-30
    4
    22
  • 上面那段代码最大的问题就是 strToArray 函数中的 let arr = new Uint16Array(str.length), 在 foo 函数每次循环执行都会在堆中生成新的数组,这里可以在 foo 函数声明一个数组,然后每次调用 strToArray 函数的时候传递 进去就可以了

    作者回复: 是的

    2020-04-30
    12
  • 阿郑
    有个疑惑,没有被GC Root遍历触达的对象就是垃圾数据。那在垃圾清理的过程中,没有被遍历到的对象是如何被标记为垃圾数据的呢?

    作者回复: 比如在标记之前,将所有对象设置为白色,然后遍历到的设置为黑色,最终白色的都视为垃圾数据

    2020-04-30
    3
    8
  • 断线人偶
    主垃圾回收器的两种算法是同时使用还是有个策略?还是说早期用的是标记 - 清除算法,现在都是使用标记 - 整理算法?

    作者回复: 同时使用的,并不是所有时候都需要做内存整理

    2020-05-24
    3
  • yunplane
    栈里的数据不需要清除吗?怎么清除?

    作者回复: 滑动下栈指针就清除了,速度非常快

    2020-05-06
    2
    3
  • luckyone
    函数里new array 会导致新生代不停触发gc,导致影响性能,改进方案可以吧array 提取出函数调用的环境这样可以放到老生代不会平凡gc

    作者回复: 没问题

    2020-04-30
    3
  • 刘长锋
    老师好: “其实这两个特点不仅仅适用于 JavaScript,同样适用于大多数的动态语言,如 Java、Python 等。” 这句话,是不是应该写成适合于大多数编程语言? 为什么适合于动态语言呢? java 是典型的静态语言吧?

    作者回复: 嗯,我修改下

    2020-05-10
    2
    2
  • Miracle
    有一个疑问:新生代在进行垃圾回收的时候,复制整理后的空闲区域和对象区域进行反转的时候,对象区域是整体清空吗,还是只清除标记的垃圾数据

    作者回复: 全部清空

    2020-04-30
    2
    2
  • 蹦哒
    请教老师:引用计数的垃圾回收机制,目前只看到iOS中使用,想知道苹果为啥选择引用计数,而其他很多语言都采用GC呢?因为GC有stop-the-world的问题,而引用计数方法貌似主要是会有循环引用问题,但是循环引用问题写代码时注意就不会有问题了,而stop-the-world是无法避免的。所以我个人更倾向于引用计数的方案,不知道老师怎么认为的呢?

    作者回复: 引用计数存在无法回收循环引用的问题,以前ie的js引擎就采用了循环引用的方式,现在都切换回来了

    2020-05-12
    2
    1
  • 草原上的骆驼🐫
    strToArray函数中的变量i,len, arr在foo函数每次循环后,都会变成垃圾数据,其中i和len会通过副垃圾回收器的Scavenge算法进行回收。arr会通过主垃圾回收器的标记回收方式回收

    作者回复: i len 本质是分配在栈上的,当前作用域执行结束就会回收掉,而arr是分配在堆中的,当前块退出后,这块数据就没用了,也没有引用了,所以这块数据就会变成垃圾数据

    2020-05-10
    2
    1
收起评论
显示
设置
留言
28
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部