简体   繁体   中英

How can I optimize a smallish array of object references for access time in V8?

I am working on a game and so have to consider small performance gains as well as large.

I was reading about array initialization in V8, in particular this article which suggests that using the format var myArray = new Array(100) is ultimately faster than var myArray = [] for small arrays (the author suggests fewer than ~1000 elements as the threshold for small).

Given a few assumptions, it isn't hard to see why. In particular, if the elements of the array are all of the same type after optimization, say, all integers, they should be pre-allocated in contiguous memory and won't cause V8 to change its internal representation of the array as described here . That will also allow the compiler to make assumptions about shape when the elements are used elsewhere.

In my situation, however, I need an array of object references, and I am able to initialize them all sequentially. So, going on what we know from above I came up with this:

 class A { constructor() { this.particles = new Array(60); for (var i = 0; i < particles.length; ++i) { this.particles[i] = new Particle(); } } } class Particle { //... } 

As the first article describes, this is the fastest way for his case of manipulating number types. So I presume that V8 assumes the size of, and allocates the space for, one of the native number types for each array. However, I am not sure which. I am also not sure how the size of an object reference compares to the size of whichever native type for which each element is allocated.

A smaller concern is, if the default element size allocation is larger than it needs to be for an array that will only ever contain references to an object (all of the same type, and also all presumed contiguous in memory), is space wasted per element with this array initialization strategy? Is there a way to avoid that? If so, is it possible to retain the optimization for access speed?

Optimizing for speed of access to each Particle , can the above initialization be improved?

V8 developer here. TL;DR: What you're doing is fine.

Preallocation and elements kind tracking are independent from each other. When you know the size you're going to need, go ahead and allocate an array with that capacity, no matter what kinds of things you're going to store in there.

That said, if you start with an empty array and grow it as you go, that's perfectly fine too. Strictly speaking, that strategy has a bit of additional cost for the growth steps, and a bit of benefit when accessing elements later, because the engine knows that all elements are present. But in the vast majority of cases, the overall difference is too small to matter, and you should just do what you find most readable/convenient.

Regarding your wondering about element sizes: on 64-bit platforms, everything has the same size (namely 64 bits ;-) ). On 32-bit platforms, pointers are 32-bit, while doubles are still 64-bit, but V8 wouldn't preallocate space for bigger elements and then waste it, so you don't need to worry about that.

Regarding your source: I'm finding it pretty difficult to make sense of that article's recommendations, so my inclination would be to disregard it. In particular, the last "trick" that's presented ( var a = []; a.length = N; instead of var a = new Array(N); ) just doesn't make any sense at all, and the given "explanation" does not apply in this case. V8 does effectively the same thing under the hood, so any difference you think you might be able to measure is pretty much guaranteed to be random noise. Beware of microbenchmarks, for they are usually misleading!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM