javascript - V8 引擎如何处理添加属性的排序?

标签 javascript performance v8

我一直在关注 Google 的 V8 Javascript 引擎的性能改进,因为我想将它整合到我自己的一个项目中。

我目前的兴趣是隐藏类。基本思想是 V8 在将属性添加到对象时创建隐藏类,以便有效地查找该属性,避免字典搜索。

例如,当您创建一个名为 p 的新 Point 对象时,它会创建一个隐藏类 C0,这是一个没有属性的类并将该类附加到对象:

enter image description here

语句 p.x = 0 将修改对象以添加属性,然后创建一个C1 指定 x 属性可以在对象内的特定偏移量处找到。

enter image description here

所以在那之后得到 p.x 是一个相对有效的操作。

最后,执行 p.y = 0 将执行类似的操作,结束时:

enter image description here

现在这实际上相当漂亮,因为如果您创建另一个 Point 对象 p2,则不需要创建新的隐藏类,它只是被“分配”给 C0。同样,按此顺序添加 xy 属性在不必创建新的隐藏类方面也很有效。


但是这个方案有两个潜在的问题。第一个涉及以下代码段发生的情况:

Point p3 = new Point();
p3.y = 3141592653589;
p3.x = 2718281828459;

在我看来,这将创建两个 隐藏类,一个在偏移量为零的位置具有 y,另一个在偏移量为零的位置具有 y和偏移量 1 处的 x

这似乎有点空间效率低下,因为两种情况下的最终类都有一个 x 和一个 y 所以应该能够共享类 C2,尽管要求您需要在对象本身中交换 xy

使转换映射更受控制会产生什么影响,例如确保属性按字母顺序存储?这样,无论您先添加 x,然后添加 y,还是添加 y,然后添加 x,您仍然会在同样的最后一个类。

这意味着在添加属性时需要做一些额外的工作,但可以大大减少隐藏类的数量。

或者这些额外的工作本身可能会消耗过多的性能吗?


第二个潜在问题是,由于此方案的全部目的是避免对对象进行字典查找,因此如何移动:

For x, see offset 0
For y, see offset 1

入类求助?

在我看来,您仍然需要在隐藏类中查找属性名称以获得对象内的偏移量。

或者我是否遗漏了一些东西并且不需要对类(class)进行字典搜索?

最佳答案

优化后,无需字典搜索(对于大多数访问)。

在属性访问时,v8 已经(希望)将属性访问转换为内联缓存 stub 。这意味着在访问 x 时,它作为 x 的标识已包含在偏移值中。所以它不再是真正的 x,甚至 x at offset 0,它只是 offset 0。尽管对象表示称为“ map ”,但它实际上只是一个偏移表。这就是使属性访问速度更快的原因。

当需要添加新属性时,问题不是“具有当前对象所有属性以及新属性的对象在哪里?”它是“对于这个对象,我需要做什么来添加这个属性?”在此基础上选择过渡。在优化代码中,不考虑现有属性的名称。删除多余的隐藏类需要一些相对繁重的操作才能找到匹配的映射。

您关于反转属性添加创建两个新的隐藏类的假设是正确的。通过使用 d8 --allow-natives-syntax 运行以下命令,您可以对此有所了解:

function Point() {}

var p = new Point();

var px = new Point();
px.x = 0x10101;

var py = new Point();
py.y = 0x20202;

var pxy = new Point();
pxy.x = 0x30303;
pxy.y = 0x40404;

var pyx = new Point();
pyx.y = 0x50505;
pyx.x = 0x60606;

var newp = new Point();
checkmaps();
newp.x = 0x70707;
checkmaps();
newp.y = 0x80808;
checkmaps();

function checkmaps() {
  var sameas = [];
  if (%HaveSameMap(newp, p))
    sameas.push("p");
  if (%HaveSameMap(newp, px))
    sameas.push("px");
  if (%HaveSameMap(newp, py))
    sameas.push("py");
  if (%HaveSameMap(newp, pxy))
    sameas.push("pxy");
  if (%HaveSameMap(newp, pyx))
    sameas.push("pyx");
  print(sameas);
}

输出是:

p
px
pxy

关于javascript - V8 引擎如何处理添加属性的排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29839226/

相关文章:

java - 用 Java 替换许多文件中的许多字符串标记的最有效方法是什么?

C++ 特征矩阵运算与内存分配性能

c++ - v8::Isolate::New 空访问冲突

javascript - 尝试一键切换容器

javascript - 为什么 Twitter 从客户端渲染转向服务器端渲染?

javascript - 获取 API - 定位 Iframe

c - Miracl 库中的执行时间

node.js - NodeJS 是否支持 JIT 预缓存?

javascript - 为什么多个内联 IF 比每个数组条目一个 IF 的循环更快

javascript - Protractor 有 "page.has_content"命令吗?