当前位置: 首页 > Web前端 > JavaScript

GoogleV8系列(一)V8如何提高对象属性的访问速度:快属性和慢属性

时间:2023-03-26 21:14:55 JavaScript

JavaScript对象是属性和值的集合,很像字典,以字符串为键,任意对象可以用作键值。但是出于性能的考虑,V8在实现对象存储的时候并没有完全使用字典的存储方式。因为字典是非线性数据结构,查询效率会低于线性数据结构。为了提高存储和搜索效率,V8采用了复杂的存储策略。一般和排序属性functionFoo(){this[100]='test-100'this[1]='test-1'this["B"]='bar-B'this[50]='test-50'this[9]='test-9'this[8]='test-8'this[3]='test-3'this[5]='test-5'this["A"]='bar-A'this["C"]='bar-C'}varbar=newFoo();for(keyinbar){console.log(`index:${key}value:${bar[key]}`)}Result:index:1value:test-1index:3value:test-3index:5value:test-5index:8value:test-8index:9value:test-9index:50value:test-50index:100value:test-100index:Bvalue:bar-Bindex:Avalue:bar-Aindex:Cvalue:bar-C可以发现:先打印数字属性,按照数字大小的顺序打印;stringattributesareprintedinorder设置打印顺序。ECMAScript规范定义:数字属性按照索引值升序排列,字符串属性按照创建顺序升序排列。我们在对象中称数字属性为排序属性,在V8中称为元素,字符串属性称为正则属性,在V8中称为属性。在V8中,为了有效提高存储和访问这两个属性的性能,使用了两个线性数据结构分别存储排序属性和正则属性。具体结构如下图所示:分解成这两个线性数据结构之后如果进行索引操作,V8会先从elements属性中依次读取所有元素,然后再读取properties属性中的所有元素,从而完成一个索引操作。fast属性和slow属性分别在elements属性和properties属性中存储了不同的属性,简化了程序的复杂度,但是在查找元素的时候多了一个步骤,比如执行bar.B语句来查找B值的属性,那么V8会先找出properties属性指向的对象属性,然后在properties对象中查找B属性。该方法在搜索过程中增加了一个操作,因此会影响元素的搜索效率。为此,V8采用了权衡策略来加快查找属性的效率。这种策略是将一些常规属性直接存储在对象本身中,这些属性称为对象内属性。对象在内存中的显示形式可以参考下图:这种方式减少了查找属性值的步骤,提高了查找效率。但是,一个对象内的属性数量是固定的,默认为10个,如果添加的属性多于为对象分配的空间,它们将保存在常规属性存储中。快速属性:存储在线性数据结构中的属性。可以通过索引访问属性,速度很快,但是当添加或删除大量属性时,会产生大量的时间和内存开销,执行效率会很低。Slowattribute:当一个对象的属性过多时,V8采用的另一种存储策略。慢速属性对象内部会有一个独立的非线性数据结构(字典)作为属性存储容器。所有的属性元信息不再线性存储,而是直接存储在属性字典中,如图:总结:对象的数字属性以线性结构存储,按索引升序排列;对象的非数字属性按顺序存储(通常)。如果属性个数少于10个,则直接存入对象(in-objectattributes);如果大于10但小于20,多出的部分存储在properties线性结构对象中;如果数量大于20,额外的属性存储在properties非线性结构对象中。