JavaScript 预分配数组未捕获 RangeError:数组长度无效

Dr.*_*ABT 20 javascript arrays

我有一个小循环的代码,它抛出 Uncaught RangeError: Invalid Array Length

\n

我能够在 Google Chrome 控制台中重现它

\n
const COUNT = 100_000_000;\nconst xValues = new Array(COUNT);\nconst yValues = new Array(COUNT);\nfor (let i = 0; i < COUNT; i++) {\n    xValues[i] = i;\n    yValues[i] = Math.sin(i * 0.000001);\n}\nconsole.log(`count: ${yValues.length}`);\n
Run Code Online (Sandbox Code Playgroud)\n

这是开发者控制台中的输出

\n

在此输入图像描述

\n

据我所知,Javascript 中的最大数组大小是 2^32-1?应该有足够的内存可以在这里分配,并且索引 i 永远不会是负数或超出数组的范围,据我所知。

\n

奇怪的是,如果我使用这段代码,就不会发生崩溃

\n
const COUNT = 100_000_000;\nconst xValues = new Array(COUNT);\nconst yValues = new Array(COUNT);\nfor (let i = 0; i < COUNT; i++) {\n    xValues[i] = i;\n    yValues[i] = i;\n}\nconsole.log(`count: ${yValues.length}`);\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

分配给 yValues[i] 的值永远不会超出 -1, +1 范围,因此我也不能将其视为数字超出范围问题。

\n

有人对此有任何了解吗?

\n

编辑:更新

\n

另一种情况不起作用。计算随机游走。

\n
    const count = 100_000_000;\n    const xValues = new Array(COUNT);\n    const yValues = new Array(COUNT);\n    let prevYValue = 0;\n    for (let i = 0; i < COUNT; i++) {\n        const curYValue = Math.random() - .5;\n\n        xValues[i] = i;\n        yValues[i] = prevYValue + curYValue;\n\n        prevYValue += curYValue;\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

这个也能扔!但

\n
    yValues[i] = i \n
Run Code Online (Sandbox Code Playgroud)\n

没问题 \xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf

\n

编辑:更新2

\n

现在可以确认这是特定于浏览器的,如果您在 Firefox 中运行相同的测试,它可以工作,但浏览器会要求您等待。

\n

怀疑异常Uncaught RangeError是错误报告的超时?

\n

Nos*_*ara 8

真正的原因在于V8内存优化。当您存储整数时,它会就地存储 32 位数字,但是当您存储双数时,它会以不同的方式存储(作为对象),因此yValues数组包含引用,但实际值存储在堆中。因此,在您的示例中,您刚刚使用了所有堆内存。要查看限制,请使用:console.memory,您将看到类似以下内容:

\n
MemoryInfo\xc2\xa0{\ntotalJSHeapSize: 10000000, \nusedJSHeapSize: 10000000, \njsHeapSizeLimit: 3760000000}\n
Run Code Online (Sandbox Code Playgroud)\n

在我的浏览器中是3_760_000_000

\n

堆上的对象占用 50+ 字节,因此我的限制约为 69_000_000 个浮点数。

\n

  • 实际上,内存中不同位置的每个值大约需要 80 个字节:-) 但有时经过优化,占用的字节数会更少。 (2认同)