# V8 引擎

# V8 垃圾回收

JavaScript 原始类型数据存放在栈中,通过移动栈顶指针 ESP 实现变量销毁,天生不需要垃圾回收。对象类型数据以及闭包空间中的数据存放在堆中,堆中的数据需要垃圾回收。

代际假说 (The Generational Hypothesis) 表明一个对象的生命周期要么很短要么很长。因此 V8 引擎实现了两种不同的垃圾回收器。

  • 副垃圾回收器负责回收新生代对象
  • 主垃圾回收器负责回收老生代对象
生命周期 体积大小
新生代对象
老生代对象

垃圾回收器执行流程:

  1. 标记非活动对象
  2. 回收非活动对象的内存
  3. 进行内存碎片整理

V8 副垃圾回收器采用 Scavenge 算法将新生区内存分为对象区域和空闲区域,两个区域轮换使用。轮换时将一个区域的活动对象复制到另一个区域,天生不会产生内存碎片。由于新生代对象体积小,所以也不会浪费太多内存。

主垃圾回收器采用 Mark-Sweep 算法。由于会产生内存碎片,因此派生出了 Mark-Compact 算法。由于老生区空间很大,一次完整回收会卡顿很久,因此派生出了 Incremental Marking 算法。

JavaScript 中分配的大对象会直接存放在老生区。小对象会先放在新生区,如果经历了两次垃圾回收还存活则会被移动到老生区,这个过程叫做对象晋升。

# V8 编译器/解释器

一些基本的编译原理常识这里就不介绍了:

  • 词法分析 (tokenize)
  • 语法分析 (parse)
  • 抽象语法树 (AST)
  • 编译和解释的输入都是 AST
  • 编译的输出是:中间代码、二进制文件/机器码
  • 解释的输出是:字节码
  • 相比字节码来说,机器码占用空间大,但执行效率高

即时编译 (JIT),是解释器和编译器配合的一种技术。在 V8 中,AST 先全部转换为字节码,Ignition 在解释执行字节码的同时,收集代码信息,当它发现某一部分代码变热了之后,TurboFan 便会把热点代码 (HotSpot) 转换为机器码。这样就实现了内存空间和执行效率的平衡。