浏览器辞典:V8

系统 浏览器
V8是Chrome的JavaScript引擎,用C++开发,基于ECMA-262第3版标准。V8的团队说Chrome对脚本的解析和执行速度是Firefox和Safari的10倍,是IE的56倍。

V8:Chrome的JavaScript引擎,用C++开发,基于ECMA-262第3版标准。作为一个开源项目,任何人都可以参加。项目地址在Google Code:http://code.google.com/p/v8/

Chrome V8设计

自从十九世纪九十年底中,Netscape浏览器集成了JavaScript,它使得web开发者更加容易访问HTML页面元素如:表单、frames和图象。JavaScript迅速流行,用于定制控件和增加动画效果。到19世纪九十年代后,出现大量的用于切换图片以响应用户生成的鼠标事件的脚本。

最近,随着AJAX的出现,JavaScript已经称为了实现基于web的应用(如:Gmail)的中心技术。JavaScript程序由简单的几行成长为几百k的源码。然而JavaScript是被设计成实现web应用的非常有效的技术。性能已经成为开发基于web的 JavaScript应用的限制因素。

V8是全新的JavaScript引擎,主要设计目标是快速执行大量JavaScript脚本应用。在几种benchmark测试中,V8的性能是JScript(IE内的引擎)、SpiderMonkey(Firefox所用)和 JavaScriptCore(safari所用)的许多倍。如果您的web应用受限于JavaScript的执行速度,则使用V8代替您当前的 JavaScript引擎将很可能提高您的应用的性能。性能提升的程度依赖于JavaScript的多少和JavaScript的特点。例如,如果在您的应用中函数倾向于一次一次被执行,则与仅执行一次许多不同函数相比性能将大大地提升。当您阅读完本文档时,您将更加清楚性能提升的原因。

V8性能的3个关键方面:

◆快速属性访问

◆动态生成机器码

◆高效的垃圾回收

快速属性访问

JavaScript是动态的编程语言:对象的属性可以增加和删除。这意味着一个对象的属性可能改变。大多数JavaScript引擎使用类似字典的数据结构存储对象的属性,每个属性的访问需要动态查找定位属性在内存的位置。这种典型的访问属性方法比在Java和Smalltalk中访问实例化变量慢得多。在这些语言中,实例化变量通过由编译器决定的根据对象类型定义的对象固定的布局定义的固定的偏移来定位。加载或存储访问非常简单,通常仅仅需要一条简单点的指令。

为了减少访问JavaScript属性的时间,V8没有使用动态查找访问属性,取而代之的是V8动态创建后台隐藏的类。这个想法不是最新才有的-是基于原型的编程语言自身的特性(相似地用于映射某些东西)(见An Efficient Implementation of Self, a Dynamiclly-Typed Object-Oriented Language Based on Prototypes)。在V8中,当一个新的属性增加时,对象改变它的隐藏类。

为了更加清除说明这一个点,想象如下一个的简单的JavaScript函数:

function Point(x, y) {  this.x = x;  this.y = y; }

当new Point(x, y)被执行时一个新的Point对象被创建。当V8首次创建时,V8创建一个初始的隐藏类Point,例子中称为C0。如果对象初始时没有任何属性则定义空的初始类。此处Point对象的隐藏的类是C0。

执行在Point里第一个语句(this.x = x;)则在Point对象中创建一个新的属性x, 这种情况下V8:

  1. 基于C0创建另外一个的隐藏类C1, 然后增加描述有属性x的信息给C1,这个属性的值存在Point对象偏移为0的位置。
  2. 如果一个x属性添加到C0描述的对象上那么隐藏类C1应该取代C0,同时更新C0以表示前面的过渡。此时Point对象的隐藏类是C1。 

执行Point的第二个语句(this.y = y; ),则在Point对象中创建一个新的属性y,这种情况下V8:

  1. 基于C1创建另外一个隐藏类C2,然后添加描述属性y的信息给C2,同时属性值在Point对象的偏移为1。
  2. 如果一个y属性添加到C1描述的对象上那么隐藏类C2应该取代C1,同时更新C1以表示前面的过渡。此时Point对象的隐藏类是C2。 

无论何时增加属性,以上似乎通过创建一个隐藏类不是很高效。然而由于类的过渡,隐藏类可以重用,实际的效率较高。第二次创建一个新的Point时是不需要创建新的隐藏类,相反新的Point对象共享了第一个Point对象的类型。例如,如果创建另外一个Point对象:

  1. 初始的Point对象没有属性,因此最新建的对象引用初始类C0。
  2. 当增加属性x,V8遵循隐藏类从C0到C1过渡。并根据C1中x的偏移写入x的值。
  3. 当增加属性y,V8遵循隐藏类从C1到C2过渡。并根据C2中y的偏移写入y的值。

尽管JavaScript比通常的面向对象的语言更加动态,使用上面方法通常的JavaScript程序的运行时行为将导致高度的结构贡献。这里列举使用隐藏类的两个优点:属性访问不需要字典查找,同时使得V8能使用面向对象的优化,内联缓存。更多的内联缓存见Efficent Implementation of the Smalltalk-80 System。

动态生成机器指令

首次执行时,V8直接将JavaScript源码编译成机器码。不存在中间过程的字节码,没有解释器。访问属性通过处理内联的缓存代码,这些代码可以像V8执行时一样转为的其他机器指令。

在首次访问一个给定对象的属性时,V8生成了对象当前的隐藏类。V8使用隐藏类内部生成内联缓存信息并通过预测这个类是否将用于在同一节代码的所有将来的对象来优化属性的访问。如果V8成功预测则属性的值将用一个简单的操作读取或者写入。如果预测不正确,则V8将删除被优化的代码。

例如,JavaScript代码访问Point对象的属性x:

point.x

在V8中,访问x的机器码是:

# ebx = the point object
cmp [ebx,<hidden class offset>],<cached hidden class>
jne <inline cache miss>
mov eax,[ebx, <cached x offset>]

如果对象的隐藏类不匹配缓存的隐藏类,则执行跳转到V8运行时系统处理内嵌缓存缺失同时生成内嵌缓存代码,通常遇到的情况是匹配,则简单地返回属性x的值。

当有许多对象具有相同的隐藏类时,则就像大多数静态语言一样这些对象都受益。使用隐藏类访问属性和内嵌缓存与机器码生成优化组合在一起,对于相同类型的对象以相似的方式频繁创建和访问,这将大大地提高执行大多数JavaScript代码的速度。

高效的垃圾回收

V8回收那些在过程中不再需要的对象的内存,这一个过程称为垃圾回收。为了确保快速的对象分配,垃圾回收时间足够短暂,没有内存碎片,V8使用了stop-the-world,分代,精确垃圾回收器。这意味着V8:

  1. 在执行垃圾回收期间停止程序的执行。
  2. 大多数的垃圾回收都是在处理一部分对象的堆。则最小化对于停止应用执行的影响。
  3. 总是精确知道何处的所有对象和指针在内存中。避免了错误的指示对象的指针可能带来的内存泄漏。

在V8中,对象的堆分成两段:刚创建对象的新空间和在垃圾回收时仍在使用的老对象。如果一个对像被垃圾回收器回收,V8更新所有指向这个对象的指针。

责任编辑:yangsai 来源: csdn博客
相关推荐

2010-07-20 15:28:09

ChakraIE9浏览器

2010-07-21 16:37:12

Nitro浏览器Webkit

2010-07-20 16:18:16

2010-07-21 15:21:08

Presto浏览器Opera

2010-07-20 15:41:39

TridentIE浏览器

2010-07-21 15:43:43

Carakan浏览器Opera

2010-07-21 16:00:40

Vega浏览器Opera

2010-07-20 16:24:38

Gecko浏览器

2010-07-21 15:06:33

2010-07-21 16:54:29

云加速浏览器

2010-07-21 16:07:02

Opera Turbo浏览器

2010-07-21 14:47:22

2010-07-20 16:01:44

GPU硬件加速浏览器

2021-09-22 08:57:46

谷歌 Chrome 94浏览器

2020-10-30 10:15:21

Chrome V8JavaScript前端

2022-06-02 12:02:12

V8C++JavaScript

2016-04-18 09:33:52

nodejswebapp

2014-11-26 09:51:24

GithubGoogleV8

2021-07-27 05:53:00

Chrome浏览器KPI

2012-03-20 11:31:58

移动浏览器
点赞
收藏

51CTO技术栈公众号