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

标签 javascript arrays optimization ecmascript-6 v8

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

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

给出一些假设,不难看出原因。特别是,如果数组的元素在优化后都是相同的类型,比如说,都是整数,它们应该预先分配在连续的内存中,并且不会导致 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 假定每个数组的一种 native 数字类型的大小,并为其分配空间。但是,我不确定是哪个。我也不确定对象引用的大小与分配每个元素的任何 native 类型的大小相比如何。

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

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

最佳答案

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

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

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

关于您对元素大小的疑问:在 64 位平台上,所有内容都具有相同的大小(即 64 位 ;-))。在 32 位平台上,指针是 32 位的,而 double 仍然是 64 位的,但是 V8 不会为更大的元素预分配空间然后浪费它,因此您无需担心。

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

关于javascript - 如何在 V8 中优化访问时间的小型对象引用数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49685157/

相关文章:

javascript - 使用 onsubmit ="return validate()"函数时文件验证不起作用

Java问题(需要帮助)

JavaScript自动类型编写器功能

c++ - C/C++中使用字符作为数组下标

c++ - atoi() 和 atof() 缓存吗?它们似乎执行得越快,调用的次数越多

c++ - 有什么方法可以更快地处理 "predictable branches"吗?

javascript - D3js 在工具提示中使用元素的当前颜色

javascript - Momentjs 弃用错误和不同的浏览器功能

python - 用于 Lucas-Lehmer 素数测试的更快的按位模数

php - 如何将mysql表作为数组传递给javascript