【问题标题】:Maximum size of an Array in JavascriptJavascript中数组的最大大小
【发布时间】:2011-09-03 13:00:52
【问题描述】:

上下文:我正在构建一个读取 rss 提要并在后台更新/检查提要的小站点。我有一个数组来存储要显示的数据,另一个存储已显示记录的 ID。

问题:在事情开始变得缓慢或迟缓之前,数组可以在 Javascript 中保存多少项。我没有对数组进行排序,而是使用 jQuery 的 inArray 函数进行比较。

网站将继续运行并更新,浏览器不太可能经常重启/刷新。

如果我应该考虑从数组中清除一些记录,那么在限制后删除一些记录的最佳方法是什么,比如 100 个项目。

【问题讨论】:

  • 浏览器从工具栏泄漏内存的问题可能比从 JS 代码泄漏的问题更多。 :) Firefox 4 我指着你。
  • 您多久检查一次数组(例如 2 秒间隔)?什么构成缓慢(例如> 500ms)?您的阵列是什么数量级(例如数千、数百万、数十亿)?
  • jsperf.com做基准测试
  • 我将每分钟检查和更新数组。是的,缓慢将是性能影响,开始影响加载和检查,以及页面上的其他动画,很难定义抱歉!
  • @Amine 感谢您的链接,看来该网站将成为我最好的新朋友 :)

标签: javascript arrays


【解决方案1】:

“它变得迟缓”之前的最大长度完全取决于您的目标机器和您的实际代码,因此您需要在那个(那些)平台上进行测试,看看什么是可以接受的。

但是,由于 ToUint32 抽象操作,根据 ECMA-262 第 5 版规范,数组的最大长度受无符号 32 位整数的限制,因此最长可能的数组可能具有232-1 = 4,294,967,295 = 42.9 亿个元素。

【讨论】:

  • @Barkermn01:ECMA-262 第 5 版规范使用抽象操作 ToUint32 来检查任何修改数组长度的操作的数组长度,所以我认为底层机器(或网络浏览器)的架构是无关紧要的。
  • hrm 很好,刚刚读到一个令人讨厌的 64 位浏览器正在燃烧毫无意义,
  • @Barkermn01,64 位浏览器还有很多其他改进。请记住,作为 javascript 解释器并不是浏览器的唯一功能。
  • Wowzer 没想到它会这么高。好的,我想我会没事的!
  • 实际上一个数组最多可以有 4294967295 (2^31-1) 个元素。见stackoverflow.com/a/12766547/396458
【解决方案2】:

无需修剪数组,只需将其寻址为循环缓冲区(索引 % maxlen)。这将确保它永远不会超过限制(实现循环缓冲区意味着一旦你到达终点,你就会再次回到起点 - 不可能超出数组的末尾)。

例如:

var container = new Array ();
var maxlen = 100;
var index = 0;

// 'store' 1538 items (only the last 'maxlen' items are kept)
for (var i=0; i<1538; i++) {
   container [index++ % maxlen] = "storing" + i;
}

// get element at index 11 (you want the 11th item in the array)
eleventh = container [(index + 11) % maxlen];

// get element at index 11 (you want the 11th item in the array)
thirtyfifth = container [(index + 35) % maxlen];

// print out all 100 elements that we have left in the array, note
// that it doesn't matter if we address past 100 - circular buffer
// so we'll simply get back to the beginning if we do that.
for (i=0; i<200; i++) {
   document.write (container[(index + i) % maxlen] + "<br>\n");
}

【讨论】:

  • 聪明的想法,但这样做可能会覆盖数据,混淆索引,并可能导致奇怪的行为。
  • 这个想法是实现一个环形缓冲区,所以是的 - 你故意“忘记”旧数据(这就是环形缓冲区的用途),这就是提问者所要求的。跨度>
  • 我只是无聊地在 SO 周围点击了一下,发现了这个响应。喜欢根据需要覆盖索引的技术。
【解决方案3】:

就像@maerics 所说,您的目标机器和浏览器将决定性能。

但对于一些真实世界的数字,在我的 2017 企业版 Chromebook 上运行该操作:

console.time();
Array(x).fill(0).filter(x => x < 6).length
console.timeEnd();
  • x=5e4 需要 16ms,对于 60fps 来说已经足够了
  • x=4e6 需要 250 毫秒,这很明显但不是什么大问题
  • x=3e7 需要 1300 毫秒,这很糟糕
  • x=4e7 需要 11000 毫秒并分配额外的 2.5GB 内存

因此,大约 3000 万个元素是一个硬性上限,因为 javascript VM 在 4000 万个元素时一落千丈,很可能会导致进程崩溃。


编辑:在上面的代码中,我实际上是用元素填充数组并循环它们,模拟应用程序可能想要对数组执行的最小操作。如果你只是运行Array(2**32-1)you're creating a sparse array,那更接近于一个有长度的空JavaScript对象,比如{length: 4294967295}。如果你真的尝试使用所有这 40 亿个元素,你肯定会导致 javascript 进程崩溃。

【讨论】:

  • 我在 Node v12.17.0、Intel Core i7 上试过,1 亿个元素占用 2.3GB 内存,约 2 秒,约 12% CPU,没有崩溃。
  • @SlawomirBrys 你跑了什么?你最终会撞上悬崖吗?在节点 v15.3.0 和核心 i9 的 macbook 上,我看到了同样的悬崖:time node -e "console.log(Array(4e7).fill(0).filter(x=&gt;x&lt;6).length)" 需要 9 秒,而长度 3e7 需要 1.1 秒。切换回 v12.17.0 我仍然得到相同的悬崖,除了慢版本需要 11 秒。
  • 我刚刚使用了new Array(size * size),其中size 是10000,所以我在数组中得到了100M 个元素。使用 2 个 for 循环遍历数组并为数组的每个元素分配一些值,大约需要 950 毫秒。我没有使用fill()filter() 函数,似乎开销是由filter() 函数引起的。
  • @SlawomirBrys 对稀疏数组进行了编辑
【解决方案4】:

您可以尝试这样的方法来测试和修剪长度:

http://jsfiddle.net/orolo/wJDXL/

var longArray = [1, 2, 3, 4, 5, 6, 7, 8];

if (longArray.length >= 6) {
  longArray.length = 3;
}

alert(longArray); //1, 2, 3

【讨论】:

  • 结束了使用切片,因为我需要从数组的开头进行修剪,不过谢谢。
【解决方案5】:

我已经构建了一个性能框架,可以操作和绘制数百万个数据集,即使这样,javascript 计算延迟也只有几十毫秒。除非您担心超出数组大小限制,否则我认为您不必担心太多。

【讨论】:

    【解决方案6】:

    它将非常依赖于浏览器。 100 个项目听起来不是一个很大的数字——我希望你可以比这个数字高很多。几千应该不是问题。可能有问题的是总内存消耗。

    【讨论】:

      【解决方案7】:

      我无耻地在内存中提取了一些相当大的数据集,尽管它确实变得缓慢,但它可能需要 15 个月以上的数据,并对数据集进行非常密集的计算。我怀疑您会遇到内存问题,除非您对数据和许多行进行大量计算。使用不同的模拟结果集进行分析和基准测试将是评估性能的最佳选择。

      【讨论】:

        猜你喜欢
        • 2017-01-10
        • 2016-07-31
        • 1970-01-01
        • 2011-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-24
        • 2012-04-06
        相关资源
        最近更新 更多