HTML and CSS Reference
Some noteworthy patterns appear. Firstly, memory usage follows roughly the trend one would expect. The
solutions involving flat arrays introduce very little overhead, occupying almost as little memory as the equivalent
native representation, which we would expect to be 48,000,000 bytes == 6 * 8 * 1,000,000 (== properties per particle *
size of property * number of particles). Particularly in the case of memory usage, the more optimal solutions appear to
have more consistent and predictable costs across browsers.
Although the effectiveness of each optimization can be seen to vary across the browsers, all the techniques
introduced so far have a measurable positive effect on both memory and execution time over all the browsers tested.
The technique we will discuss next had a measurable, but less uniform, impact on the measurements.
ArrayBuffers and ArrayBufferViews
and writing native types (at the level of signed or unsigned bytes, shorts, ints, as well as float and double values).
Intended in part for manipulating graphics data (such as vertex, index, or texture buffers) in a format that can be
directly consumed by graphics hardware, ArrayBuffers and ArrayBufferViews also introduce many opportunities for
Broadly, an ArrayBuffer represents a contiguous memory buffer with no type information, and an
ArrayBufferView (such as Int8Array or Float32Array) represents a “window” onto some subregion of that buffer,
exposing the memory as an array of specific native types. Multiple ArrayBufferViews of different types can point to
regions of the same ArrayBuffer, and can overlap with each other. A slightly more complex particle structure that uses
floating point and lower precision integer data is illustrated by Listing 4-8.
Listing 4-8. Combining Different Native Data Types into a Single Memory Buffer
// Implementation of this native structure:
// struct Particle
// float position_x, position_y, position_z;
// float velocity_x, velocity_y, velocity_z;
// uint16_t timeToLive, flags;
// Particle stride in bytes: 6*4 + 2*2 = 28
// Particle stride in words: 7
// Particle stride in half words: 14
// The underlying memory buffer
var particlesBuffer = new ArrayBuffer(numParticles * 28);
// Access the buffer as float32 data
var particlesF32 = new Float32Array(particlesBuffer);
// Access the buffer as uint16_t data, offset to start at
// 'timeToLive' for the first particle.
var particlesU16 = new Uint16Array(particlesBuffer, 6*4);
// 'position' and 'velocity' for the i-th particle can be accessed:
// particlesF32[(7*i) + 0] ... particlesF32[(7*i) + 5]
// 'timeToLive' and 'flags' for the i-th particle is accessed as:
// particlesU16[(14*i) + 0] and particlesU16[(14*i) + 1]