简单理解v8执行过程

228 阅读2分钟

解释器:

像是短跑选手, 启动很快, 但是长时间的跑步就有点慢了.

编译器:

像是长跑选手, 启动慢一点, 但是长跑就比较厉害.

v8 = 编译器 + 解释器

v8使用JIT(Just In Time)技术, 就是编译器+解释器.

意思就是开始先用解释器执行代码,

但是碰到重复执行的热点代码, 就优化到解释器中执行.

这样第一次启动也快了, 长时间的执行也能逐步优化.

v8的执行流程

image.png

准备阶段:

在 V8 启动执行 JavaScript 之前,还需要准备执行 JavaScript 时所需要的一些基础环境,

  • “堆空间” — 内存模型
  • “栈空间” — 内存模型
  • “全局执行上下文” — 执行过程中的全局信息
  • “全局作用域” — 用来查找变量
  • “消息循环系统” — 消息驱动器, 消息队列, 让v8运行起来
  • “内置函数” — 内置的方法

执行阶段:

基础环境准备好之后,就可以执行的 JavaScript 代码了

  1. 首先 v8 需要将代码结构化成抽象语法树(AST), 这样的树形结构 v8 比较方便遍历和解析.
  2. 生成AST的同时, 还会生成 作用域, 作用域是用来查找变量的
  3. 生成字节码, AST 和 机器代码的中间代码,
  4. 进入解释器, 解释字节码, 并且输出执行结果
  5. 如果某段代码重复执行, 则这段代码会被标记为 热点代码,
  6. 标记完了v8将这段代码进入优化编译器, 将热点代码优化编译后得到二进制代码
  7. 再次执行热点代码的时候, 则直接使用二进制代码
  8. 一旦执行过程中对象结构被修改了, 会触发反优化操作,下次执行就会回退到解释器中执行了.

总结

运行一段代码, 就像是做一道菜,

  1. 需要将食材处理好, 切块, 切片, 切丁(AST),
  2. 然后用小碗装起来(作用域), 什么黄瓜条, 萝卜丁, 肉块, 方便找到使用,
  3. 再然后就开始炒菜了, 按着菜谱(字节码), 先放油,再放辣椒, 再放肉, 就是一步一步的放入锅里(解释器)
  4. 然后就装盘了, 开吃.
  5. 然后发现真好吃, 还想再吃一盘, 但是老得切 葱姜蒜 (热点代码)好麻烦, 就每次多切一点葱姜蒜, 装起来, 下次再炒的时候, 直接用, 减少做饭的时间.
  6. 但是呢, 有时候我们可能需要的蒜, 需要整颗的, 就需要重新拨一个蒜(反优化操作).

这样其实就是v8执行一段代码的过程.