【问题标题】:How does hidden classes really avoid dynamic lookups?隐藏类如何真正避免动态查找?
【发布时间】:2022-01-21 20:38:04
【问题描述】:

所以我们都听说 v8 使用了一种叫做隐藏类的东西,当许多对象具有相同的形状时,它们只存储一个指向存储固定偏移量的形状结构的指针。我已经听过这句话一​​百万次了,我非常了解这如何减少了很多内存使用(不必为每个地图存储一个地图真是太棒了),并且可能因为它的性能更快一些。

但是我仍然不明白它是如何避免动态查找的。我听到的唯一一件事是在字符串(字段名称)和固定偏移量之间存储缓存,并且每次都检查它,但如果缓存未命中(很可能发生),仍然会有动态查找。

每个人都说这几乎和 C++ 字段访问一样快(通常只是一条mov 指令),但是这个 1 字段访问缓存甚至还不够接近。

看下面的函数:

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

v8 如何让x 字段的访问速度如此之快,避免动态查找?

【问题讨论】:

  • "如果缓存未命中(很可能发生)" - 不,在普通代码中不太可能。
  • 一个我不确定的细节:缓存 1 条目的大小是多少?我的意思是通常对象有超过 1 个字段,所以我想这应该很常见......也许不太可能,但肯定很常见
  • 对象有多少属性并不重要。重要的是.x 总是指同一个。
  • @Bergi:您为什么不将您的答案发布为答案,以便可以投票/接受?

标签: javascript node.js optimization v8


【解决方案1】:

(这里是 V8 开发人员。)

关键是隐藏类允许缓存。因此,当然,仍然需要一些动态查找。但是由于缓存,它们不必在每次执行像 o.x 这样的属性访问时都重复。

基本上,第一次调用示例函数getx 时,它必须进行完整的属性查找,并且它会缓存被查询的隐藏类和查找结果。在随后的调用中,它会简单地将传入的o 的隐藏类与缓存的数据进行比较,如果匹配,它会使用缓存的有关如何访问该属性的信息。当然,在不匹配时,它必须再次回退到动态查找。 (实际上它有点复杂,因为涉及到额外的权衡,但这是基本思想。)

因此,如果一切顺利,单个动态查找就足以调用任意数量的此类函数。在实践中,事情经常进展顺利,如果您从一个非常简单的 JS 引擎开始,并且没有执行任何此类技巧,并且您添加了动态查找结果的缓存,那么您可以预期全面提高大约 10 倍的性能。添加一个优化编译器可以让这个想法更进一步,并将缓存的结果直接嵌入到优化的代码中;这可以很容易地再提供 10 倍的改进并接近 C 类的性能:代码仍然需要包含隐藏的类检查,但在成功检查时可以使用一条指令读取属性。 (这也是为什么 JS 引擎不能“立即优化所有内容”,即使他们想这样做:优化关键取决于填充良好的缓存。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-09
    • 2021-10-23
    • 2019-10-04
    • 2015-01-27
    • 1970-01-01
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多