JavaScript中是否有理想的数组大小?

16
我在各种语言中看到过一些小实用程序,针对所需数组容量,会计算出一个“理想大小”来。通常情况下,当分配的数组大于容量时,会使用这些程序。它们通常通过计算数组长度来工作,使得分配的块大小(以字节为单位)加上内存分配开销等于给定容量所需的最小精确2的幂。根据内存管理方案,这可以显着减少内存碎片化,因为内存块被分配然后释放。
JavaScript允许构建具有预定义长度的数组。那么,“理想大小”概念适用吗?我可以想到四个反对意见(无特定顺序):
  • JS内存管理系统的工作方式不会从这种策略中受益
  • JS引擎已经在内部实现了这样的大小策略
  • JS引擎实际上并不将数组保存为连续的内存块,因此整个想法是没有意义的(除了类型化数组)
  • 这个想法是适用的,但内存管理是如此依赖于引擎,以至于没有一个单一的“理想大小”策略是可行的
另一方面,也许所有这些论点都是错误的,一个小实用程序实际上会产生效果(即:在脚本性能方面产生可衡量的差异)。
因此:是否可以为JavaScript数组编写有效的“理想大小”程序?

1
我支持“..一个小的[基准]实用程序例程实际上会有效地确定实现性能”。 - user2864740
1
这个问题非常依赖于具体的引擎。 - Sterling Archer
1
稀疏数组更像其他语言中的assocArrays,因此我怀疑是否会有一致的好处。此外,在数组中使用undefined也意味着混合类型数组,这会导致V8对结构进行封装并严重减慢IO速度。 - dandavis
你多常会创建一个固定大小的数组?个人而言,我从来没有这么做过,所以对我来说并不存在“理想大小”吧。 - Sterling Archer
@dandavis 如果你执行 Arrray(2014),浏览器很可能会期望你紧接着填充2014个值,并为此做好准备。 - John Dvorak
对我来说,理想的数量就是我实际需要的数量。当然,在选择缓冲区大小时无法应用此原则。 - John Dvorak
3个回答

8
在JavaScript中,数组本质上是对象。它们仅通过API表现为数组。使用参数初始化数组仅使用该值设置长度属性。

如果传递给Array构造函数的唯一参数是介于0和232-1(包括边界)之间的整数,则返回一个新的JavaScript数组,并将其长度设置为该数字。-Array MDN

此外,没有数组“类型”。数组是对象类型。因此,它是一个Array Object ecma 5.1

因此,在使用时不会有内存使用方面的区别。

var one = new Array();
var two = new Array(1000);

除了长度属性之外。在使用Chrome的内存时间轴进行循环测试时,这也是正确的。在我的机器上创建1000个每个都会导致大约2.2MB的分配。
一个 输入图像描述

听起来很像我的第三个要点。 :) - Ted Hopp
我刚刚注意到你的回答中提到了这一点:“此外,没有数组“Type”。数组是一个对象类型。” 我知道JavaScript不是一种有类型的语言,但我特别指的是类型化数组,比如UInt8ArrayFloat64Array等。它们为JavaScript提供了一种访问内存缓冲区中原始二进制数据的机制(即ArrayBuffer对象)。 - Ted Hopp

1
你需要测量性能,因为有太多的动态部分。虚拟机、引擎和浏览器。然后,是虚拟内存(平台windows/linux,可用物理内存和质量存储设备HD/SSD)。显然,还有当前负载(存在其他网页或服务器端,其他应用程序)。
我认为这种努力没有什么用处。任何关于性能的理想大小,在另一个选项卡在浏览器中加载或在另一台机器上加载页面时,可能不再理想。
在这里改进的最好方法是开发时间,写得更少,更快地部署您的网站。

0

我知道这个问题和答案都与内存使用有关。但是,尽管调用两个构造函数(带有和不带有大小参数)之间可能没有分配的内存大小差异,但在填充数组时性能存在差异。 Chrome引擎显然执行了一些预分配,如Chrome分析器中运行的此代码所示:

<html>

<body>
<script>
    function preAlloc() {
        var a = new Array(100000);
        
        for(var i = 0; i < a.length; i++) {
            a[i] = i;
        }
    }

    function noAlloc() {
        var a = [];
        var length = 100000;
        for(var i = 0; i < length; i++) {
            a[i] = i;
        }
    }

    function repeat(func, count) {
        var i = 0;
        while (i++ < count) {
            func();
        }
    }
</script>
</body>
Array performance test
<script>
    // 2413 ms scripting
    repeat(noAlloc, 10000);
    repeat(preAlloc, 10000);
    
    
</script>
</html>

性能分析器显示,没有大小参数的函数花费了28秒来为1000次分配和填充10万个项目的数组,而在数组构造函数中使用大小参数的函数则仅花费了不到7秒钟。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接