如何在 V8 中优化访问时间的小型对象引用数组?

How can I optimize a smallish array of object references for access time in V8?

我正在开发一款游戏,因此必须考虑小的性能提升和大的性能提升。

我正在阅读 V8 中的数组初始化,特别是 this article,这表明对于小型数组,使用 var myArray = new Array(100) 格式最终比 var myArray = [] 快(作者建议少于~1000个元素作为small的阈值)。

给出一些假设,不难看出原因。特别是,如果数组的元素在优化后都是相同的类型,比如说,都是整数,它们应该预先分配在连续的内存中,不会导致 V8 改变其数组的内部表示 as described here.这也将允许编译器在其他地方使用元素时对形状做出假设。

然而,在我的情况下,我需要一个对象引用数组,并且我能够按顺序对它们进行初始化。所以,继续我们从上面知道的,我想出了这个:

class A {
    constructor() {
        this.particles = new Array(60);
        for (var i = 0; i < particles.length; ++i) {
            this.particles[i] = new Particle();
        }
    }
}
class Particle {
    //...
}

正如第一篇文章所描述的,这是他处理数字类型的最快方法。所以我假设 V8 假定每个数组的一种本机数字类型的大小,并为其分配 space。但是,我不确定是哪个。我也不确定对象引用的大小与分配每个元素的本机类型的大小相比如何。

一个较小的问题是,如果默认元素大小分配大于它需要的数组,该数组将只包含对对象的引用(所有类型相同,并且所有假定在内存中都是连续的) ,使用此数组初始化策略每个元素是否浪费了 space?有没有办法避免这种情况?如果是这样,是否可以保留访问速度的优化?

正在优化每个的访问速度Particle,上面的初始化是否可以改进?

这里是 V8 开发人员。 TL;DR:你做的很好。

预分配和元素种类跟踪相互独立。当您知道您将需要的大小时,请继续并分配一个具有该容量的数组,无论您要在其中存储什么类型的东西。

就是说,如果您从一个空数组开始并随着时间的推移增长它,那也完全没问题。严格来说,该策略对增长步骤有一点额外的成本,并且在稍后访问元素时有一点好处,因为引擎知道所有元素都存在。但在绝大多数情况下,整体差异太小无关紧要,你应该只做你发现最多的 readable/convenient.

关于您对元素大小的疑问:在 64 位平台上,所有内容都具有相同的大小(即 64 位 ;-))。在 32 位平台上,指针是 32 位的,而双精度数仍然是 64 位的,但是 V8 不会为更大的元素预分配 space 然后浪费它,所以你不需要担心这个。

关于您的来源:我发现很难理解那篇文章的建议,所以我倾向于忽略它。特别是,最后出现的 "trick"(var a = []; a.length = N; 而不是 var a = new Array(N);)根本没有任何意义,给定的 "explanation" 不适用于这种情况. V8 在引擎盖下有效地做同样的事情,所以你认为你可以测量的任何差异几乎可以保证是随机噪声。当心微基准测试,因为它们通常具有误导性!