1

上文v8中快属性和慢属性讲到快属性和慢属性,搞清楚了v8中对象的属性查询是怎么样的。今天来看看为了加快对象的查询,v8还做了什么事情。

隐藏类

还是拿下面的构造函数来举例子

    function Foo(elNum, pNum) {
        for (let i = 0; i < elNum; i++) {
        this[i] = 'ele' + i;
    }

        for (let i = 0; i < pNum; i++) {
        this['pp' + i] = 'property' + i;
    }
}
var a = new Foo(10, 10);
var b = new Foo(10, 10);
var c = new Foo(20, 10);
var j = new Foo(0, 10);

上述的实例中,我们看看它们的隐藏类是什么,elements和properties哪些会影响隐藏类的形状。

image.png
image.png
image.png
image.png

我们可以看到全部对象的map的指向都是@141629,说明上面几个对象的隐藏类是指向同一个。说明了elements的个数不影响隐藏类,隐藏类只记录properties的形状

我们现在给a添加一个字段,看看隐藏类会有什么变化。

a.ppCustom = 'property comstom';

image.png
由于我刷新了页面,所以这里指向发生了变化,不过我们只看相对变化就可以。b/c/j的map都指向了@151345,而a的map变成了@151391。发生了变化,说明当对象的形状发生了变化的时候,隐藏类需要对应生成一个新的。
但是由于v8引擎考虑到了开发的时候既然会增加属性,也会有可能删除属性,所以map中有一个back_pointer字段,指向上一次map的地址
image.png
看看a的map的back_pointer,指向了@151345,跟大家的是一样的。如果后续执行又把ppCustom删除了,那么会沿着back_pointer链寻找匹配的隐藏类,如果匹配到则使用该隐藏类,避免了频繁增删属性导致频繁的生
成新的隐藏类。

隐藏类中存储了各个属性的偏移量
image.png
这样在查找属性的时候会先看隐藏类中的偏移量,然后直接取址获取数据。
image.png
我们再看看上图,这个对象(超过30个字符串属性)的map没有back_pointer和discriptor,说明当超过30个字符串属性的时候不再使用隐藏类。

结合之前的快属性的讲解,总结一下properties的查询:

  1. 如果初始化的时候字符串属性小于30个,则会生成隐藏类,查询通过隐藏类中的偏移量寻址取值,在已经存在隐藏类的情况下,新增的属性也会生成隐藏类;
  2. 如果初始化的时候字符串属性大于30个,则不会有隐藏类。初始化就有的字符串属性则直接通过外层直接获取,新增的属性则通过properties进行慢查询。

内联缓存

function load(o) {
    return o.x;
}

通常v8获取o.x的流程是:查找对应对象o的隐藏类,再通过隐藏类查找x属性偏移量,然后取址获取值。
如果这个方法反复被执行,能不能不用经过隐藏类的查询就可以获取值呢?
答案是可以的

这个加速策略就是内联缓存。

v8在执行函数的过程中,会观察函数中的一些调用点(CallSite)的中间数据,然后将这些数据缓存起来,当下次执行的时候,直接利用这些中间数据获取值。有效提高重复代码的执行效率。

内联缓存为每个函数维护一个反馈向量,反馈向量其实是一个表结构,每一项称为插槽(slot)

slottypestatemapoffset
0LOADMONO233214DkDK4

例如上述load函数的反馈向量如上表所示。
slot表示插槽id,type有LOAD加载类型和STORE存储类型等,state有单态mono/多态poly/超态maga
当执行到调用点的时候,到对应的插槽中寻找属性的偏移量,大大提升了v8的执行效率。

var o = { x: 1, y: 2};
var o2 = { x: 2, y: 3, z: 4 };
load(o);
load(o2);

如果反复调用load函数的时候,传入的对象隐藏类不同,那么会在同一个插槽中存储多个map信息。

slottypestatemapoffset
0LOADMONO233214DkDK -> 888999DkDK4 -> 4

在一个插槽中如果只有一个map信息称为单态,有2-4个map信息称为多态,超过4个map信息称为超态。
所以在编码习惯上,最好相同数据结构的数据进行批量处理,减少不同数据结构的数据交叉处理的情况。

所以,都快2021年了,你拥抱TS了吗?


一画先生
83 声望12 粉丝

我司长期招聘前端开发工程师,有意的小伙伴+vx: Mr_yihua