V8 developer here. In short: Mike 'Pomax' Kamermans' guess is spot on.
32 * 1024 * 1024 == 2**25 is the limit up to which new Array(n)
will allocate a contiguous ("C-like") backing store of length n
. Filling such a backing store with zeroes is relatively fast, and requires no further allocations.
With a longer length, V8 will create the array in "dictionary mode"; i.e. its backing store will be an (initially empty) dictionary. Filling this dictionary is slower, firstly because dictionary accesses are a bit slower, and secondly because the dictionary's backing store needs to be grown a couple of times, which means copying over all existing elements. Frankly, I'm surprised that the array stays in dictionary mode; in theory it should switch to flat-array mode when it reaches a certain density. Interestingly, when I run var a = new Array(32 * 1024 * 1024 + 1); for (var i = 0; i < a.length; i++) a[i] = 0;
then that's what happens. Looks like the implementation of fill
could be improved there; on the other hand I'm not sure how relevant this case is in practice...
Side notes:
at 32MB + 1 elements
we're not talking about 32 MB here. Each entry takes 32 or 64 bits (depending on platform and pointer compression), so it's either 128 or 256 MB for 2**25 entries.
node starts allocating memory without limit, as if it were stuck in an infinite loop
The operation actually does terminate after a while (about 7 seconds on my machine), and memory allocation peaks at a little over 900 MB. The reason is that if you actually use all entries, then dictionary mode is significantly less space efficient than a flat array backing store, because each entry needs to store its index, its attributes, and the value itself, plus dictionaries by their nature need some unused capacity to avoid overly many hash collisions.
I am using Array in this example because it replicates the behavior of another, more complex problem
Given how specific the behavior seen here is to arrays, I do wonder how accurately this simplified case reflects behavior you're seeing elsewhere. If the real code you have does not allocate and fill huge arrays, then whatever is going on there is probably something else.