博客 阅读时间 4 分钟

借助 V8 引擎提升性能:设计选择研究

分享本文
Boost Performance with V8 Engine: A Design Choices Study

V8 引擎是 Google 开源的高性能 JavaScript 引擎,用 C++ 编写。除了 Google Chrome,它还出现在 MongoDB、Node.js 以及许多其他流行的应用程序中。

探究 V8 为何如此快速、采用了哪些技术来达到这样的性能水平,是一件很有意思的事。

OOP、设计模式与性能

一些 C/C++ 程序员持有一种错误的观念,认为使用 OOP 和设计模式会降低应用程序的性能。V8 就是一个很好的例子,说明事实未必如此:V8 实现了许多设计模式,而且优化得很好。

下面是它用到的一些模式:

工厂模式

当 JavaScript 引擎执行脚本时,会为遇到的每个变量、函数或数组创建一个实例。JSObject 是所有这些对象的父类。

下面是继承自 JSObject 的所有类的列表:

v1

V8 实现了一个工厂类来创建所需的对象,Factory::NewJsObject 方法就是为此服务的。

下面是所有使用它的方法:

v4

工厂并不被 V8 的类直接使用;它是由 Heap 类调用的,这为实现又增加了一层间接性。

访问者模式

正如访问者模式维基页面所解释的:

The visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to follow the open/closed principle.

与工厂模式一样,这个模式也给实现增加了一些间接性,但它让代码更可读、更易维护。

V8 源代码中有许多类实现了访问者模式。

v2

尽管 V8 的开发者需要优化执行性能,他们仍然愿意在代码中引入一些间接性。诚然,使用设计模式和某些 C++ 机制会因为实现中增加的间接性而影响性能,但那更多是微优化层面的问题。真正显著的宏观优化,更多取决于针对应用程序需求量身定制的设计选择。

V8 为优化执行而做的设计选择

1. 隐藏类与快速属性访问

JavaScript 是一门动态编程语言:属性可以随时被添加到对象上或从对象中删除。这意味着对象的属性会随时间变化。

如前所述,JSObject 是 JSFunction(代表 JavaScript 函数)或 JSValue(代表 JavaScript 值)的父类。然而,并没有哪个继承自 JSObject 的类来代表 Function 或 Value 这样的“类”。大多数 JavaScript 引擎使用类似字典的数据结构来存储对象属性;每次属性访问都需要一次动态查找,以确定属性在内存中的位置。

这种方式使得 JavaScript 中的属性访问通常比 Java 和 Smalltalk 等语言中的实例变量访问慢得多。在那些语言中,由于对象的类定义了固定的对象布局,实例变量位于由编译器确定的固定偏移处。访问仅仅是一次内存读取或写入,通常只需要一条指令。

V8 使用隐藏类(hidden class)的概念来减少访问 JavaScript 属性所需的时间。V8 不使用动态查找来访问属性,而是在幕后动态地创建隐藏类。

2. 动态机器码生成

V8 在首次执行时就把 JavaScript 源代码直接编译成机器码。没有中间字节码,也没有解释器。属性访问由内联缓存(inline cache)代码处理,这些代码可能会在 V8 执行过程中被其他机器指令修补。

3. 高效的垃圾回收器

V8 通过一个称为垃圾回收的过程,回收不再需要的对象所占用的内存。为了确保快速的对象分配、短暂的垃圾回收停顿以及无内存碎片,V8 采用了“停止一切”(stop-the-world)、分代式、精确的垃圾回收器。这意味着 V8:

  • 在执行垃圾回收周期时暂停程序运行。
  • 在大多数垃圾回收周期中只处理对象堆的一部分,从而把暂停应用程序的影响降到最低。
  • 始终确切知道所有对象和指针在内存中的位置,从而避免把对象误认为指针——这种误判可能导致内存泄漏。

结语

仅仅因为性能是您的首要目标就选择不使用 OOP 和设计模式,可能是个糟糕的主意:您也许能赢得几微秒,却牺牲了代码的可读性和可维护性。

真正显著的宏观优化,更多取决于针对应用程序需求量身定制的设计选择。

分享本文