在 V8 中,为什么预分配数组消耗的内存更少?

In V8 why does a preallocated array consume less memory?

考虑以下两种选择:

  const mb_before = process.memoryUsage().heapUsed / 1024 / 1024;
  const n = 15849;
  const o = 115;
  const entries = [];
  for (var i = 0; i < n; i++) {
    const subarr = [];
    for (var j = 0; j < o; j++) {
      subarr.push(Math.random());
    }
    entries.push(subarr);
  }
  const mb_after = process.memoryUsage().heapUsed / 1024 / 1024;
  console.log('arr using ' + (mb_after - mb_before) + ' megabyte');
  // arr using 15.110992431640625 megabyte

  const mb_before = process.memoryUsage().heapUsed / 1024 / 1024;
  const n = 15849;
  const o = 115;
  const entries = new Array(n);
  for (var i = 0; i < n; i++) {
    const subarr = new Array(o);
    for (var j = 0; j < o; j++) {
      subarr[j] = Math.random();
    }
    entries[i] = subarr;
  }
  const mb_after = process.memoryUsage().heapUsed / 1024 / 1024;
  console.log('arr using ' + (mb_after - mb_before) + ' megabyte');
  // arr using 12.118911743164062 megabyte

根据我的理解,这两个数组的大小应该是相同的,只是它们的实例化方式不同。如何解释产生的内存使用量始终不同?

我认为这与分配数组内存的方式有关。当您像第二个示例中那样实例化一个给定特定大小的数组时,它将分配该内存。

当您增大数组时,它会分配少量额外的 space 来处理增长,然后随着您增大数组,额外的内存分配会变大。这导致在第一个示例中有额外的空闲 space。

我一点也不觉得奇怪。尽管标准数组 aren't really arrays at all*,JavaScript 引擎默认优化:尽可能将它们视为真正的数组。

在您的第一个示例中,V8 不知道每个数组将变得有多大——它只是不断增长,以便将其视为优化数组(而不是具有特殊属性的对象) ,V8 必须不断地重新分配和复制以使其周期性地变大。因此,最近的主动分配留下了很多额外空间以防它继续增长也就不足为奇了。

在你的第二个例子中,你已经提前给了 V8 一个重要的线索,告诉你你打算把数组做成多大。因此,V8 使用该信息来优化它为底层真实数组所做的分配是合理的。


* (这是我贫血的小博客上的 post)