V8引擎为啥这么快

函数内联(InLining) 

  🚀 V8引擎内联机制,是一切优化的基础
  比如有一个封装的函数,在任意位置调用,V8会直接函数调用替换为该函数的实际代码

function func1(a, b) {
  return a + b;
}

function func2(x, y) {
  return func1(x, y) + 10;
}

🫡 会被直接转换为:

function func2(x, y) {
  return x + y + 10;
}

  当然,触发内联机制机制也是有条件,主要有以下要求:

  1. 不能有 argumentstry-catchwith 语法、参数。
    1. try-catch,虽然新版V8优化了该问题,但是还是会影响性能。👉 深入了解
  2. 简短的函数
    1. 这也是“高内聚、低耦合”的概念,不要把很多逻辑全部塞在一起,V8也难以解偶优化哦
  3. 函数被频繁调用

隐藏类(Hidden Class

💡C++、Java这类语言每个变量,都会有一个唯一确定的类型。在编译阶段就可以确定对象中的偏移量等信息,CPU就可以直接调用对象首地址(C++中是this指针)。

  JavaScript动态语言,变量可以随时被任意类型对象赋值,对象本身也可以随时增加、删除成员。访问对象属性需要的信息,完全由运行时确定。为了按索引的方式访问成员,🚀 V8引擎内部实现对象分类隐藏类V8内部的一种数据结构,本身也属于一个对象。下面给一个例子:

// 调用 Point 会创建一个 “引隐藏类” C0
function Point(x, y) {
// 基于 C0(Point) 变量x 被创建成C1 ,C1描述了找到X属性在内存中的位置(相当于this)
  this.x = x; 
// 这里的 y 会被创建成 C2
  this.y = y;
}

// 🎉 隐藏类转换性能,取决于属性添加的顺序,顺序不同,创造的隐藏类不同。
var p1 = new Point(1, 2);
p1.a = 5;
p1.b = 6;
// 🎉 如p2 也能跟p1一样赋值a、b 则性能最优
var p2 = new Point(3, 4);
p2.b = 7;
p2.a = 8;

内联缓存(Inline Caching) 

 🚀 V8对象访问过程: 获取隐藏类地址   通过属性名查找偏移值 计算属性地址

  JavaScript是动态语言,JIT运行过程中,对象的属性访问,会反复执行。内联缓存功能,就是把执行访问过程隐藏类偏移值属性地址)给缓存起来。

  内联缓存功能,大致思路,就是将初次查找的隐藏类、偏移值保存起来,下次查找,先比较当前对象是否是之前的隐藏类,如果不是就重新创建隐藏类、查找偏移值、计算属性地址的逻辑。

函数内联(Machine Code) 

 🚀 V8为了提升JavaSctipt执行效率,编译器直接生成机器码(优化回退

JavaScript在运行过程中,会采集函数的执行次数。若频繁执行,将会被V8引擎标记为热点函数

针对热点函数,V8会直接编译成机器码。若遇到类型变化🚀V8将会退回编译成机器字节码

垃圾回收机制 (GC)

  🚀 V8引擎的垃圾回收机制、算法,是当今 JavaScript 性能优化的核心。同时,也是 “空间换时间” 的典型用例。

  简单来说, V8引擎通过 分代管理增量并发算法机制,在保证垃圾回收效率的同时,提升了 JavaScript 的执行效率。

  网络上关于 JavaScript 垃圾回收的文章太多太多,简单几句话也聊不完,我单开一篇文章,与大家详聊。

  👉 点击此处预览