Regarding V8:
For Boolean, number, string, null, and void 0 literals in V8, they only take a constant 4/8 bytes of memory for the pointer or immediate integer value embedded in the pointer. There is no heap allocation for these as a string literal will just be internalized. However, exceptions can occur with big integers or doubles which may require boxing with additional bytes. In optimized code, local doubles can remain unboxed in registers or stack, or an array exclusively containing doubles may store them unboxed.
To see the generated code snippet, click here:
function weird(d) {
var a = "foo";
var b = "bar";
var c = "quz";
if( d ) {
sideEffects(a, b, c);
}
}
The pointers to the strings are hard-coded in this example, avoiding any allocation.
Object identities typically require 12/24 bytes for plain objects, 16/32 bytes for arrays, and 32/72 bytes for functions (plus additional bytes if a context object needs allocation). To avoid heap allocation here, bleeding edge V8 along with function inlining is necessary.
Consider the following example:
function arr() {
return [1,2,3]
}
The values 1,2,3 share a copy-on-write array but unique identity objects need to be allocated. Returning an array from an upper scope can prevent frequent identity allocations. For a simpler alternative, check out this code snippet.
If you encounter memory issues with JS, dynamic function creation could be the culprit. Hoist functions to a level where they don't need recreation to improve performance. Opt for static functions whenever possible.
Excessive memory usage matters in JavaScript as it is traced by garbage collector affecting performance. Run the following snippet with tracing options to observe:
var l = 1024 * 1024 * 2
var a = new Array(l);
for( var i = 0, len = a.length; i < len; ++i ) {
a[i] = function(){};
}
Compare with using a static function instead:
var l = 1024 * 1024 * 2
var a = new Array(l);
var fn = function(){};
for( var i = 0, len = a.length; i < len; ++i ) {
a[i] = fn;
}