在 V8 上:
布尔值、数字、字符串、null 和 void 0 字面量为指针或嵌入在指针中的立即整数值占用恒定的 4/8 字节内存。但是这些根本没有堆分配,因为字符串文字只会被内部化。例外可以是大整数或双精度数,它们用 4/8 字节的盒子指针和 12-16 字节的盒子装箱。在优化的代码中,本地双精度值可以在寄存器或堆栈中保持未装箱状态,或者始终仅包含双精度值的数组将它们未装箱存储。
考虑the meat of the generated code:
function weird(d) {
var a = "foo";
var b = "bar";
var c = "quz";
if( d ) {
sideEffects(a, b, c);
}
}
如您所见,指向字符串的指针是硬编码的,不会发生分配。
对象标识对于普通对象至少占用 12/24 字节,对于数组占用 16/32 字节,对于函数占用 32/72 字节(如果需要分配上下文对象,则 + ~30/60 字节)。如果您运行最前沿的 v8 并且身份没有逃逸到无法内联的函数中,那么您只能在没有堆分配的情况下逃脱。
例如:
function arr() {
return [1,2,3]
}
值 1、2、3 的后备数组将作为写入时复制数组被函数返回的所有数组共享,但对于需要分配的每个数组仍然是唯一的标识对象。看看generated code is 有多复杂。因此,即使进行了这种优化,如果您不需要数组的唯一标识,只需从上层范围返回一个数组即可避免每次调用函数时分配标识:
var a = [1,2,3];
function arr() {
return a;
}
Much simpler.
如果你在 js 中遇到内存问题而没有做任何看似疯狂的事情,那么你肯定是在动态创建函数。将所有功能提升到不需要重新创建的水平。从上面可以看出,考虑到大多数代码都可以通过利用this 来摆脱静态函数,仅仅函数的标识已经很胖了。
因此,如果您想从中获取任何东西,如果您的目标是性能,请避免非 IIFE 关闭。任何表明它们不是问题的基准都是错误的基准。
您可能有直觉,当您拥有 8GB 时,额外的内存使用量有什么关系。好吧,这在 C 中无关紧要。但在 Javascript 中,内存不仅仅坐在那里,它还被垃圾收集器跟踪。那里的内存和对象越多,性能就越差。
只要考虑运行类似的东西:
var l = 1024 * 1024 * 2
var a = new Array(l);
for( var i = 0, len = a.length; i < len; ++i ) {
a[i] = function(){};
}
--trace_gc --trace_gc_verbose --print_cumulative_gc_stat。 Just look how much work 是白做的。
与静态函数比较:
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;
}