Recently, I had to work on optimising a task that involved the creation of really large arrays (~ 10⁸ elements).
I tested a few different methods, and, according to jsperf, the following option seemed to be the fastest.
var max = 10000000;
var arr = new Array(max);
for (let i = 0; i < max; i++) {
arr[i] = true;
}
Which was ~ 85% faster than
var max = 10000000;
var arr = [];
for (let i = 0; i < max; i++) {
arr.push(true);
}
And indeed, the first snippet was much faster in my actual app as well.
However, my understanding was that the V8 engine was able to perform optimised operations on array with PACKED_SMI_ELEMENTS
elements kind, as opposed to arrays of HOLEY_ELEMENTS
.
So my question is the following:
- if it's true that
new Array(n)
creates an array that's internally marked withHOLEY_ELEMENTS
, (which I believe is true) and - if it's true that
[]
creates an array that's internally marked withPACKED_SMI_ELEMENTS
(which I'm not too sure is true)
why is the first snippet faster than the second one?
Related questions I've been through:
Create a JavaScript array containing 1...N
Most efficient way to create a zero filled JavaScript array?
Recently, I had to work on optimising a task that involved the creation of really large arrays (~ 10⁸ elements).
I tested a few different methods, and, according to jsperf, the following option seemed to be the fastest.
var max = 10000000;
var arr = new Array(max);
for (let i = 0; i < max; i++) {
arr[i] = true;
}
Which was ~ 85% faster than
var max = 10000000;
var arr = [];
for (let i = 0; i < max; i++) {
arr.push(true);
}
And indeed, the first snippet was much faster in my actual app as well.
However, my understanding was that the V8 engine was able to perform optimised operations on array with PACKED_SMI_ELEMENTS
elements kind, as opposed to arrays of HOLEY_ELEMENTS
.
So my question is the following:
- if it's true that
new Array(n)
creates an array that's internally marked withHOLEY_ELEMENTS
, (which I believe is true) and - if it's true that
[]
creates an array that's internally marked withPACKED_SMI_ELEMENTS
(which I'm not too sure is true)
why is the first snippet faster than the second one?
Related questions I've been through:
Create a JavaScript array containing 1...N
Most efficient way to create a zero filled JavaScript array?
- 3 IIRC packed vs holey isn't that much of a performance difference, it's just an internal marker that the array needs to be treated differently (especially given that many things changed in V8 since that talk). Also, the performance difference should be observed in using the array, not in creating and initialising it. What exactly did you benchmark, your whole app or only the two snippets you posted? – Bergi Commented Feb 1, 2019 at 14:59
- @Bergi thanks, do you have any link to some documentation about this? In terms of benchmark, I measured the performance of a function that involved the creation and the usage of the array (the latter being the same in both cases) – bugs Commented Feb 1, 2019 at 15:03
- 1 I found the link to one of @jmrk's answers: stackoverflow./a/53161007/1048572 (see the ments for discussion of holey vs packed). Not sure whether that question is duplicate-worthy. – Bergi Commented Feb 1, 2019 at 15:08
1 Answer
Reset to default 13V8 developer here. The first snippet is faster because new Array(max)
informs V8 how big you want the array to be, so it can allocate an array of the right size immediately; whereas in the second snippet with []
/.push()
, the array starts at zero capacity and has to be grown several times, which includes copying its existing elements to a new backing store.
https://www.youtube./watch?v=m9cTaYI95Zc is a good presentation but probably should have made it clearer how small the performance difference between packed and holey elements is, and how little you should worry about it.
In short: whenever you know how big you need an array to be, it makes sense to use new Array(n)
to preallocate it to that size. When you don't know in advance how large it's going to be in the end, then start with an empty array (using []
or new Array()
or new Array(0)
, doesn't matter) and grow it as needed (using a.push(...)
or a[a.length] = ...
, doesn't matter).
Side note: your "for loop with new Array() and push" benchmark creates an array that's twice as big as you want.