认识 V8 引擎(1)- V8 的由来

V8 是一个由 Google 开发的,开源的,高性能的, JavaScript 及 WebAssembly 引擎,使用 C++ 编写。广泛应用于 Google Chrome 浏览器、Node.js 等等。跨平台支持 Windows(Win7以上)、macOS(10.12+),以及各种 Linux 系统,包括 ARM 的手机系统。同时,V8 也可以独立的运行使用,嵌入集成到 C++ 的应用中。

JavaScript 引擎的主要作用是执行 JavaScript 代码。世界上第一款 JavaScript 引擎是 SpiderMonkey,由布兰登·艾克在网景公司开发,用于 Netscape Navigator 网页浏览器。传闻艾克在 1995年 5 月仅花了十天就把原型设计了出来。

早期的 JavaScript 引擎是通过解释器的方式解释执行,比如将源码转成抽象语法树(AST),然后解释执行,其运行效率并不高。但由于早期的浏览器网页还是以静态网页(HTML)为主,JavaScript 并未被广泛重度的应用,所以解释执行并未遇到太大问题。后来随着动态网页兴起,网页里开始运行越来越多复杂的应用,JavaScript 的瓶颈凸显了出来。

既然 JavaScript 运行性能不行,为什么不替换它呢?换成 Lua,Python 不香吗?或者再重新精心设计另外一门专用语言(WebAssembly)。其实替换 JavaScript 的尝试一直都在进行,但是JavaScript 在浏览器里的地位至今无人能撼动。主要原因我认为有三个:

  1. 经过几十年的应用,JavaScript 已经成为事实标准,改变不易
  2. JavaScript 对开发者非常友好,上手较其他语言更容易
  3. 随着 JIT 技术的引入,JavaScript 的性能已经不再是问题

前两个都是习惯问题,即使改变,慢慢也就适应了。但 JIT 技术的引入,几乎解决了 JavaScript 的性能问题,使得 JavaScript 的地位更加的牢固。在 JavaScript 中应用 JIT 的典型代表,就是我们今天的主角:V8。在引入我们的主题之前,我还要简要的介绍一下什么是 JIT 技术。

JIT 的全程是 just-in-time compilation,又译即时编译或实时编译。在 JIT 出现之前,高级编程语言要被计算机执行,通常通过两种方式来实现:AOT 和解释器。AOT 全程 ahead-of-time compilation,即代码预先通过编译器的编译,直接生成目标机器的机器码。因此它的运行效率最高,比如我们常用的 C/C++ 代码,通过 gcc/clang/msvc 等编译器,直接编译出机器码的二进制文件,其运行性能我们称之为原生性能。

既然 AOT 性能最高,全都用 AOT 不就得了?也不尽然。AOT 要求编译的代码是静态类型的,比如一个变量的类型在运行期间不允许变成另一种类型,也不允许动态的往类型里增加属性。而 JavaScript 是动态类型的,比如下面一段代码,变量 foo 的类型可以运行时随时变化:

var foo = 1; // foo is a int
foo = "hello"; // foo change to a string

function Point() {

}
foo = new Point(); // foo change to a Point
foo.x = 10;  // foo add x property
foo.y = 10;  // foo add y property

foo 类型总是变来变去,给 AOT 编译器增加了很大的麻烦。同时,AOT 还有编译时间长,生成的目标文件大的问题。它不能像 Java 一样『一次编译,到处运行』,而是针对不同平台『编译多次,到处运行』。如果想像 JavaScript 一样做到『一次编写,到处运行』,就需要在用户的浏览器端,运行时实时的进行编译。这样一来,缓慢的编译过程又拖慢了代码的启动速度。

JIT 结合了 AOT 和解释器两者的优势。它可以运行时根据情况在两者之间切换。比如首次启动时,使用解释器来执行,这样保证了代码的启动速度,对于一些短小的一次性执行的代码非常友好。当代码运行一段时间,编译器发现某些代码频繁的反复执行,则切换到 JIT 模式即时的将这部分代码编译成机器码,之后再运行到这类代码时,则可以做到几乎以原生的速度执行。

现代语言的虚拟机几乎都拥有了 JIT 的能力。如 JVM JIT,LuaJIT。几大 JavaScript 引擎,例如微软的 Chakra、Mozilla 的 SpiderMonkey、苹果的 JavaScriptCore、谷歌的 V8,JIT 已经成了标配功能。而其中谷歌的 V8,是所有的 JavaScript 引擎的佼佼者。

为什么 V8 能做到这么优秀呢?我们后面慢慢来讲。我们先来看看 V8 是怎样诞生出来的。从维基百科里了解到,V8 的创建者是一名叫 Lars Bak 的丹麦程序员。我们来看看这位大神的履历:

  1. 1991 年在 Sun 工作,开发 Self 虚拟机,成为业界最佳程序员之一
  2. 1994 年,离开 Sun,加入 LongView,设计和开发了高性能虚拟机 StrongTalk
  3. 1997 年,LongView 被 Sun 收购,主导开发了著名的 Java 虚拟机 HotSpot
  4. 2002 年回到丹麦,创立名叫 OOVM 的公司。2004年将公司卖给一家瑞士公司 Esmertec,随后又在该公司干了两年
  5. 2006 年加入谷歌,在丹麦自己的农场开始开发 V8 引擎
  6. 2008 年,开发的 V8 引擎和谷歌浏览器 Chrome 一起横空出世。V8 处理 JavaScript 的速度比当时的 IE 浏览器快 56 倍
  7. 2011 年主导开发并发布 Dart 语言。如今应用火热的 Flutter 正是使用该语言进行开发

据说 2006 年是劈柴(Sundar Pichai,现谷歌 CEO)哥亲自给 Bak 打的电话,说谷歌正打算开发一款全新的浏览器,你来做高级经理,开发一个高性能的 JavaScript 引擎好不好?Bak 对开发 JavaScript 引擎很有兴趣,欣然接受了这份工作。但他说他不在乎当什么高级经理,在乎的是推动打破技术的边界,并且他不会回到加州,而是在丹麦自己的农场开始他的工作。他家农场距离加州总部相隔 8000 公里,相差了 9 个时区。

他在农场建立了办公室,家就在办公室对面。每天,他走过石子路到办公室,然后开始写代码。结束工作后,又穿过院子走回家,把工作彻底放下。他享受这种工作和生活分开的感觉。这也是他不想去硅谷的原因。他招募了自己的学生卡斯帕伦德一起来农场工作,命名了新的引擎名字叫 V8,以汽车 V 型 8 缸发动机命名,预示着这将是一款性能爆表的引擎。V8 从零开始开发的,一面世就秒杀了市面上所有的 JavaScript 引擎。

早期的 V8 版本,为了追求性能的极致,将源码转成抽象语法树之后,直接通过 Full-codegen 生成目标机器码。 2010 年,又推出了 Crankshaft 编译优化器,在代码执行过程中,内置的 Profiler 记录热点函数,然后提交给 Crankshaft 进行优化,生成优化后的机器码,进一步提高执行的效率。

由于直接生成目标机器码,导致了占用内存大,编译时间长导致启动速度慢,2016 年 V8 设计了中间字节码 Ignition,以让 V8 能在内存更小的安卓设备上流畅的运行。2017 年推出 V8 5.9 版本,废弃了旧的 Full-codegen+Crankshaft 的编译架构,使用了 Ignition 字节码解释器和编译优化器 TurboFan,内存使用得到进一步降低,网页加载速度也得到大幅的提升。Ignition+TurboFan 的组合沿用至今。

2017 年 V8 5.7 版本,正式支持了 WebAssembly,一个基于浏览器设计的新的字节码标准。2018 年 V8 6.9 版本,引入 WebAssembly 基线编译器 Liftoff,极大提升了首次编译的效率,配合 TurboFan 编译优化器,在启动速度和运行性能上都得到了很大的提升。

截止目前,V8 最新的版本是 8.7,并且一直在不断的迭代进化之中。

随想

Lars Bak 从大学时才接触计算机,一直专注在虚拟机的领域,做出像 JVM HotSpot、V8、Dart 这样非凡的产品。这告诉我们,找准自己的兴趣和努力的方向,深耕下去,什么时候开始都不会迟。Bak 加入谷歌时,已经 41 岁。虽然之前他已经积累了不少的财富,但我相信他是由衷的不在乎谷歌的什么高级职位,在乎的只是用更好的技术,突破更多的技术边界。所以 V8 从一开始就是开源的,正如题图 2008 年 Chrome 发布时的宣传漫画里说的一样:『所以,其他浏览器也可以用它(V8),或者,如果有其他项目需要用到 JavaScript,开发者都可以直接使用 V8』

我喜欢写代码,但有时也因程序员 35 岁问题而困扰,了解了 Lars Bak 经历之后,我想,专研深耕自己的领域,专注到兴趣的事情来上,竞争力自然就加强了,也就真没有什么好焦虑了。

微信扫一扫交流

作者:CoderZh
微信关注:hacker-thinking (程序员思考者)
本文出处:https://blog.coderzh.com/2021/01/16/v8-1/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。