Javascript Hidden Classes and Inline Caching in V8

Hidden Classes

Javascript,众所周知是一门动态类型语言,也就是说当一个对象被实例化之后,我们仍然可以随意的添加或者删除它的属性。例如,下面的代码中,我们实例化了一个car,包含有makemodel两个属性,同时,当car被实例化了之后我们仍可以将其他属性year赋予它。

```javascript
var car = function(make,model) {
    this.make = make;
    this.model = model;
}

var myCar = new car(honda,accord);

myCar.year = 2005;

大多数的JavaScript解释器通过类字典(dictionary-like,基于hash的)型的对象来存储对象中的属性。这样,相对于非动态类型语言(比如Java),这种结构的数据类型让我们在获取对象属性时会消耗更多的时间。在Java中,所有的对象属性会在编译之前就被一个固定的对象层所决定,同时在运行时不可修改。因此,这些属性的值(或者指向属性的指针)可以一个接一个的连续得存储在内存中,每一个属性都有一个固定的偏移量。偏移量可以简单的通过属性的类型决定,显而易见,由于JavaScript是一门动态类型语言,所以无法在运行时确定偏移量。

在非动态类型语言中,例如Java只需要一条指令就可以确定一个属性在内存中的位置,然而JavaScript则需要多条指令来从Hash Table中获得位置。这就导致在JavaScript中属性查找通常会比其他语言慢很多。

鉴于基于字典的存储方式非常的低效,V8采用了一个完全不同的方式:Hidden Class。除了JavaScript是在运行时完成一系列操作之外,Hidden Class的工作原理和Java中对待对象的处理方式很类似。在阅读剩下的文章时,请记住V8会给每一个对象都赋予一个Hidden Class,Hidden Class的终极目的就是优化属性的查询时间。现在我们来具体看看。

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

var obj = new Point(1,2);

一旦一个新的function被声明,JavaScript就会紧接着创建一个Hidden Class C0

enter image description here
enter image description here

由于暂时还没有属性,所以C0是空的。

当执行到this.x = x时,V8会创建第二个Hidden Class叫做C1C1是基于C0的。C1描述了如何找到属性x,也就是x在内存中的位置。在这个例子中,简化为将x存在偏移值为0的位置,这表明当我们在内存中查看Point对象时,第一个偏移所在的位置会保存属性x。V8同时会用class transitionC0更新,简单来说就是Hidden Class现在切换为C1了。换句话说,C1就变成了Point对象的Hidden Class。

enter image description here
enter image description here

每当对象有新属性加入时,旧的Hidden Class就会通过一个过渡路径(transition path)更新为新的Hidden Class。这种过渡非常重要,因为这保证了用相同方式创建的两个对象可以共享同一个Hidden Class。如果有两个对象共享同一个Hidden Class,同时又有一个属性同时添加给了这两个对象,则这种过渡操作保证了新的Hidden Class仍然是这两个对象的Hidden Class。

this.y = y执行时,重复之前的操作。一个新的叫做C2的Hidden Class被创建,一个过渡会添加给C1,同时Hidden Class转换为C2Point对象的Hidden Class现在就被更新为了C2

enter image description here
enter image description here

注意:Hidden Class的过渡取决于属性被添加的顺序。

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

var obj1 = new Point(1,2);
var obj2 = new Point(3,4);

obj1.a = 5;
obj1.b = 10;

obj2.b = 10;
obj2.a = 5;

var obj2 = new Point(3,4);为止,obj1和obj2共享同一个Hidden Class。但是,由于属性ab在之后被添加的顺序不同,导致了Hidden Class过渡时走向和不同的路径。

enter image description here

通过上述的例子,也许你直观上会觉得obj1和obj2拥有不同的Hidden Class并没有什么关系。因为每一个Hidden Class都保存着合适的偏移量,那么不管obj1和obj2有没有共享同一个Hidden Class,他们获取属性的速度应该是一样的。为了理解为什么这样的想法是错的,让我们来学习一个V8中的优化技术,叫做内联缓存(inline caching)。

内联缓存

V8利用了一个在动态类型语言中常用的优化技巧,内联缓存。简单来说,内联缓存依赖于同类型对象的同一方法的重复调用。

那么这是怎么实现的呢?V8维护了一个缓存——最近被调用的函数中,被作为参数传递的对象类型,然后利用这些信息并假设这种对象类型在将来仍然会被作为参数传递。如果V8能正确的做出这种预测,那么它就能绕过寻找对象属性的过程,直接从对象的Hidden Class中寻找之前存好的信息。

好的,那么Hidden Class的思想是这么和内敛缓存相结合起来的呢?当一个特定的对象的方法被调用时,V8引擎需要利用对象的Hidden Class来决定用哪个偏移量来寻找属性。当针对同一个Hidden Class的方法被成功调用两次,V8就会跳过Hidden Class的属性寻找,直接将属性的偏移量绑定到对象的指针上。当该方法再次被调用时,V8引擎假定Hidden Class没有被修改,我们可以直接用上次在Hidden Class中查找到的属性偏移量来去内存中寻找具体的值。这大大提高了执行的速度。

这就是为什么属性的添加顺序显得很重要了。如果属性的添加顺序不同,两个对象的Hidden Class就不同,也就无法使用内敛缓存优化了。

enter image description here

当然,鉴于JavaScript仍然是门动态类型语言,所以总会有判断失误的时候。这时候就需要返回传统的方法,利用Hidden Class来获取属性的偏移量了。

一些优化技巧

  1. 实例化对象时永远保存属性的顺序相同。
  2. 给对象增加新的属性时,会导致Hidden Class更新,同时针对旧Hidden Class的优化失效,导致速度变慢。因此,尽量在构造函数中确定好对象的属性。
  3. 运行同一个方法多次会比运行多个方法一次要快的多(参照内联缓存)。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容