2017-02-22 65 views
0

考虑以下两种选择:在V8中,为什么preallocated数组消耗更少的内存?

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 

从我的理解这两个数组大小应该是相同的,他们只实例化不同的方式。如何解释由此产生的内存使用情况始终不同?

+0

一句话?优化。 –

+0

@ T.J.Crowder感谢您的纠正;仍然想知道如何基于数组实例化的方法以不同的方式优化数据量的持久性 – Tom

+0

对不起,并不意味着我的删除评论作为*更正*,正如一个合议的笑话。对不起,如果没有遇到。 –

回答

2

我相信这与阵列内存分配的方式有关。当你在第二个例子中给它一个特定大小的数组时,它会分配这个内存。

当您增长数组时,它将分配少量的额外空间来处理增长,然后随着数组的增长,额外的内存分配将变得更大。这会在第一个示例中产生额外的可用空间。

+1

(V8开发者在这里)这是正确的。当你使用'Array(n)'构造函数时,V8可以根据需要分配尽可能多的空间。当您创建一个空数组(使用'[]'或'new Array()')并向其中添加元素时,V8将以大块方式生成后备存储,因此当您停止添加元素时,可能仍有一些未使用预先分配的后台存储。 – jmrk

1

我根本没有发现这个惊喜。虽然标准数组aren't really arrays at all *,JavaScript引擎默认优化:尽可能将它们视为真正的数组。在你的第一个例子中,V8不知道每个数组有多大,它只是不断增长,为了把它当作优化数组(而不是具有特殊属性的对象) ,V8必须不断重新分配和复制,以使其周期性变大。所以最近的主动分配在保持增长的情况下留下了很多额外空间也就不足为奇了。

在你的第二个例子中,你已经给出了V8在你打算创建这个数组的大小之前的一个很大的线索。所以V8会使用这些信息来优化它为底层真实数组所做的分配是合理的。


* (这是我的一点贫血博客的一篇文章)