今天主要分析v8引擎是如何编译与执行JS代码,我们带着以下思考来阅读这篇文章。
1. 思考- 为什么需要使用V8引擎
- JavaScript代码被执行分为哪几个阶段
- AST到底是做什么用的
在讲V8之前,我们需要先来了解以下JS语言类型,语言类型大致可分为编译型语言和解释型语言:
- 编译型语言:代码在运行之前直接将代码转换为机器代码。
- 解释型语言:同样也需要将其转换为机器代码,但是和编译型语言的区别在于是在运行时根据需要进行转换。
很显然,编译型语言执行比较快,而JS是解释型语言需要边运行边将其转换为机器认识的机器代码。
3. V8是编译与执行浏览器代码上图就是V8编译与执行浏览器代码的过程,下面我们将会对此过程进行解析:
- Parse阶段:V8引擎负责将JS代码转换成AST(抽象语法树)
- Igition阶段:解释器将AST转换成字节码,解释字节码也会为下一个阶段编译优化提供需要的信息。
- TurboFan阶段:编译器利用上个阶段收集的信息,将字节码优化为机器码
- Orinoco阶段:垃圾回收阶段,程序将不在使用的内存空间进行回收(图中未显示)
TurboFan编译器是JIT优化编译器,TurboFan的编译线程和生成字节码不会在同一线程上这样可以和Igintion解释器相互配合使用,不受另一方的影响。
接下来我们将对各个阶段进行详细的分析:
- 生成AST
主要进行以下两个工作:
- 词法分析:
这个阶段会将源代码拆成最小的,不可再分的词法单元,称为token,代码中的空格在JS中是直接忽略的。
- 语法分析:
这个过程是将词法单元转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树,这个树被称为抽象语法树
2. 生成字节码
思考:为什么不直接将代码转换成机器码呢?而是先将其转换成字节码?
个人认为先转换成字节码再生成机器码主要有以下两点好处:
- 直接转换会带来内存占用过大的问题
因为抽象语法树(AST)全部生成机器码,而机器码比字节码占用的内存大多了
- 某些JavaScript使用场景使用解释器更为合适
解析成字节码,发现很多代码没必要生成机器码,尽可能减少了内存占用过大的问题。
进入生成字节码阶段,将AST转换成字节码后,内存占用显著下降,同时也可以使用JIT(及时编译)编译器做进一步优化。可以将字节码理解为机器码的一种抽象。
3. 生成机器码
如果发现一段代码被重复执行多次的情况,生成的字节码以及分析数据会传给turboFan编译器,它会根据分析数据的情况生成优化好的机器码。
由Igition解释器收集的分析数据被TurboFan编译器使用,主要是通过一种推测优化手段的技术,生成已经优化的机器码来执行。
4. 垃圾回收
V8引擎会将不在使用的程序代码占用的内存空间进行释放,前面有blog进行了讲解,但是并不是很完全,少了一种(全停顿的介绍)
- 全停顿
我们知道,JavaScript 是单行线语言,运行在主线程上。一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。这种行为叫做全停顿。
在 V8 新生代的垃圾回收中,因其空间较小,且存活对象较少,所以全停顿的影响不大。但老生代中,如果在执行垃圾回收的过程中,占用主线程时间过久,主线程是不能做其他事情的,需要等待执行完垃圾回收操作才能做其他事情,这将就可能会造成页面的卡顿现象。
为了降低老生代的垃圾回收而造成的卡顿,V8 将标记过程分为一个个的子标记过程,同时让垃圾回收标记和 JavaScript 应用逻辑交替进行,直到标记阶段完成,这个算法称为增量标记算法。
使用增量标记算法可以把一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他的 JavaScript 任务中间执行,这样当执行代码时,就不会让用户因为垃圾回收任务而感受到页面的卡顿了
暑期编程PK赛 得CSDN机械键盘等精美礼品!


