V8 JavaScript 对象与二叉树
V8 JavaScript Object vs Binary Tree
有没有比使用 JavaScript
Object
?
This may be outdated but it suggests a new class is dynamically generated for every single property. Which made me wonder if a binary tree implementation might be faster, however this does not appear to be the case.
二叉树的实现不是很好的平衡,因此通过平衡可能会变得更好(只有前 26 个值是手动大致平衡的。)
有没有人知道为什么或如何改进它?另一方面:动态 class 概念是否意味着实际上有 ~260,000 个属性(在第二个 link 的 jsperf 基准测试中)以及随后的动态 class 定义链保存在内存中?
V8使用了'maps'的概念,描述了对象中数据的布局。
这些映射可以是 "fast maps",它指定从对象开始的固定偏移量,在该处可以找到特定的 属性,或者它们可以是 "dictionary map",它使用提供查找机制的哈希表。
每个对象都有一个指向描述它的地图的指针。
通常,对象从快速地图开始。当将 属性 添加到具有快速地图的对象时,该地图将转换为描述新 属性 在对象内的位置的新地图。如有必要,将为新数据项重新分配足够的 space 对象,并将对象的映射指针设置为新映射。
旧地图记录了它的转换,包括指向新地图的指针和对 属性 的描述,属性 的添加导致了地图转换。
如果另一个具有旧映射的对象得到相同的 属性 添加(这很常见,因为相同类型的对象往往以相同的方式使用),该对象将只使用新地图 - 在这种情况下,V8 不会创建新地图。
但是,一旦属性的数量超过某个阈值(实际上,当前指标与使用的存储space有关,而不是实际的属性数量),对象将更改为使用字典映射。此时使用哈希表重写对象。通常,它不会再经历任何映射转换 - 添加的任何更多属性只会进入哈希表。
快速映射允许 V8 生成优化代码(使用 Crankshaft),其中对象内 属性 的偏移量被硬编码到机器代码中。这使得它在可以执行此操作的情况下非常快 - 它避免了进行任何查找的需要。
显然,生成的机器代码依赖于地图——如果对象的数据布局发生变化,代码必须被丢弃并在必要时重新优化。 V8 有一个类型分析机制,可以在执行未优化代码期间收集有关各种对象类型的信息。在满足某些稳定性约束之前,它不会触发代码优化 - 其中之一是函数中使用的对象映射不经常更改。
Here's a more detailed description of how this stuff works.
对于您的特定测试用例,我认为它会在准备循环中添加属性时经历数百次映射转换,然后它最终会转换为基于字典的对象。它肯定不会通过其中的260,000。
关于您关于二叉树的问题:一个适当大小的哈希表(具有合理的哈希函数和其中大量的对象)在您只是搜索的用例中总是优于二叉树,因为您的测试代码似乎可以(所有插入都在设置阶段完成)。
有没有比使用 JavaScript
Object
?
This may be outdated but it suggests a new class is dynamically generated for every single property. Which made me wonder if a binary tree implementation might be faster, however this does not appear to be the case.
二叉树的实现不是很好的平衡,因此通过平衡可能会变得更好(只有前 26 个值是手动大致平衡的。)
有没有人知道为什么或如何改进它?另一方面:动态 class 概念是否意味着实际上有 ~260,000 个属性(在第二个 link 的 jsperf 基准测试中)以及随后的动态 class 定义链保存在内存中?
V8使用了'maps'的概念,描述了对象中数据的布局。
这些映射可以是 "fast maps",它指定从对象开始的固定偏移量,在该处可以找到特定的 属性,或者它们可以是 "dictionary map",它使用提供查找机制的哈希表。
每个对象都有一个指向描述它的地图的指针。
通常,对象从快速地图开始。当将 属性 添加到具有快速地图的对象时,该地图将转换为描述新 属性 在对象内的位置的新地图。如有必要,将为新数据项重新分配足够的 space 对象,并将对象的映射指针设置为新映射。
旧地图记录了它的转换,包括指向新地图的指针和对 属性 的描述,属性 的添加导致了地图转换。
如果另一个具有旧映射的对象得到相同的 属性 添加(这很常见,因为相同类型的对象往往以相同的方式使用),该对象将只使用新地图 - 在这种情况下,V8 不会创建新地图。
但是,一旦属性的数量超过某个阈值(实际上,当前指标与使用的存储space有关,而不是实际的属性数量),对象将更改为使用字典映射。此时使用哈希表重写对象。通常,它不会再经历任何映射转换 - 添加的任何更多属性只会进入哈希表。
快速映射允许 V8 生成优化代码(使用 Crankshaft),其中对象内 属性 的偏移量被硬编码到机器代码中。这使得它在可以执行此操作的情况下非常快 - 它避免了进行任何查找的需要。
显然,生成的机器代码依赖于地图——如果对象的数据布局发生变化,代码必须被丢弃并在必要时重新优化。 V8 有一个类型分析机制,可以在执行未优化代码期间收集有关各种对象类型的信息。在满足某些稳定性约束之前,它不会触发代码优化 - 其中之一是函数中使用的对象映射不经常更改。
Here's a more detailed description of how this stuff works.
对于您的特定测试用例,我认为它会在准备循环中添加属性时经历数百次映射转换,然后它最终会转换为基于字典的对象。它肯定不会通过其中的260,000。
关于您关于二叉树的问题:一个适当大小的哈希表(具有合理的哈希函数和其中大量的对象)在您只是搜索的用例中总是优于二叉树,因为您的测试代码似乎可以(所有插入都在设置阶段完成)。