V8 JavaScript引擎研究(二)高性能探秘

V8的高性能探秘

V8项目负责人Lars Bak:V8的全部优化都不是原创的。V8组合了过往对于动态语言的各类优化技术,于是具备了很是高效的性能。编程

快速属性访问

JavaScript是动态编程语言,这意味着能够动态的增长或删除对象的属性。缓存

以往实现

大多数的JavaScript引擎都是使用相似字典的数据结构来保存一个对象的属性,在这种结构下每次访问一个属性都须要动态查找其在内存中的位置。数据结构

  • 优点:

    实现简单。编程语言

  • 劣势:

    效率低。相对于Java、Smalltalk等语言,因为对象的class有着固定的布局,所以属性在内存中有着由编译器生成相对于对象的固定位移,所以访问属性要快得多,可能仅须要一条机器指令。布局

V8的实现

为了减小访问属性的耗时,V8没有使用动态动态查找来访问属性。性能

V8为每一个对象建立了一个隐藏类(Hidden Class),每当增长一个属性时更换新的隐藏类。优化

举例说明:this

1 function Point(x, y)
2 { 3   this.x = x; 4   this.y = y; 5 }

当调用 new Point(x, y) 时产生一个新的Point对象,V8这样来处理:首先建立一个Point的隐藏类,在此例中假设叫C0,此时对象没有任何属性,初始时类是空的。在此阶段,Point对象的隐藏类为C0。spa

当执行Point里的第一条语句 this.x = x; 建立Point对象的一个新属性x。这时V8建立另一个基于C0的隐藏类C1,而后在C1中增长描述信息,指明Point对象拥有属性x,并存储在相对于Point对象的位移0处。同时更新C0的类转移信息,指明当基于C0隐藏类的对象增长了属性x时,此对象的隐藏类将由C0替换为C1。在此阶段,Point对象的隐藏类为C1。指针

当执行Point里的第一条语句 this.y = y; 建立Point对象的一个新属性y。这时V8建立另一个基于C1的隐藏类C2,而后在C2中增长描述信息,指明Point对象也拥有属性y,并存储在相对于Point对象的位移1处。同时更新C1的类转移信息,指明当基于C1隐藏类的对象增长了属性y时,此对象的隐藏类将由C1替换为C2。在此阶段,Point对象的隐藏类为C2。

不管什么时候只要增长一个属性就建立一个隐藏类,这种作法彷佛看上去很是低效,然而因为类的转移信息,隐藏类能够被重用。想象一下这样的场景,当下一次一个新的Point对象被建立后,就再也不须要建立新的隐藏类,新的Point对象将共享为第一个Point对象所建立的一系列隐藏类,具体过程以下:

初始化一个没有任何属性的Point对象,此时初始的隐藏类C0适用于此对象。

当增长属性x后,V8遵循从C0到C1的类转移信息,而后在C1指定的位移处写入x的值。

当增长属性y后,V8遵循从C1到C2的类转移信息,而后在C2指定的位移处写入y的值。

虽然JavaScript比大多数面向对象的语言更加动态,但绝大多数JavaScript程序的运行时行为致使了高度使用上述方法的共享结构。

  • 优点:

    不须要使用动态查找字典来访问对象的属性,尤为是当建立大量相同的对象时效率大幅提高。

    可让V8使用基于隐藏类的优化技术-内联缓存(Inline Caching)。

  • 劣势:

    实现略复杂。

    每次对象新增属性都须要建立一个新的隐藏类,极端状况下效率很是低。

内联缓存&动态机器码生成

V8的内联缓存依托于隐藏类技术,这里的内联与C++中的内联是两个不一样的概念。

当第一次执行JavaScript代码时V8直接将其编译成机器码,而不产生中间的字节码。(*Google已经发布了新的JavaScript解释器Ignition,旨在减小内存消耗,在一些内存有限的设备上使用)

在第一次指定访问一个给定对象的属性的代码时,V8会肯定此对象的隐藏类。V8预测将来在此代码段上执行的全部对象属性访问都拥有相同的隐藏类,并将属性访问的代码经过使用此隐藏类,打进使用内联缓存访问指令的补丁(一般即为一条对内存偏移地址的访问指令,也就是内联的概念)。若是V8预测命中,则大大优化了属性访问耗时;若是V8未命中,则将打进的补丁代码移除,从新建立隐藏类并访问属性。

这样在处理大量相同类型的对象并频繁建立和访问时(绝大多数JavaScript代码都是如此执行),效率将极大提高。

高效的垃圾回收实现

V8垃圾回收机制简介

V8在运行时自动回收再也不须要使用的对象内存,也便是垃圾回收。

V8使用了全暂停式(stop-the-world)、分代式(generational)、精确(accurate)等组合的垃圾回收机制,来确保更快的对象内存分配、更短的垃圾回收时触发的暂停以及没有内存碎片。

V8的垃圾回收有以下几个特色:

  • 当处理一个垃圾回收周期时,暂停全部程序的执行。
  • 在大多数垃圾回收周期,每次仅处理部分堆中的对象,使暂停程序所带来的影响降至最低。
  • 准确知道在内存中全部的对象及指针,避免错误地把对象当成指针所带来的内存泄露。
相关文章
相关标签/搜索