我正在尝试优化一个移动应用程序,并且想知道哪些内容占用了最小的内存空间(我意识到这可能因浏览器而异):
- 对象指针
- 布尔文本
- 数字文本
- 字符串文本
理论上哪个应该占用最少的内存空间?
我正在尝试优化一个移动应用程序,并且想知道哪些内容占用了最小的内存空间(我意识到这可能因浏览器而异):
理论上哪个应该占用最少的内存空间?
在 V8 引擎中:
布尔值、数字、字符串、null 和 void 0 字面量占用常量 4/8 字节的内存,用于指针或嵌入在指针中的立即整数值。但是,对于这些字面量根本没有堆分配,因为字符串字面量只会被内部化。异常情况包括大整数或双精度浮点数,它们将被装箱处理,并使用 4/8 字节作为盒子指针和 12-16 字节作为盒子的大小。在优化代码中,局部双精度浮点数可以保持未装箱状态存储在寄存器或堆栈中,或者一个仅包含双精度浮点数的数组将以未装箱状态存储它们。
考虑生成代码的核心部分:
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的支持数组作为写时复制数组,但每个数组仍需要分配唯一标识对象。查看生成的代码可以看到这是多么复杂的。因此,即使使用了此优化,如果您不需要数组的唯一标识,只需从上层作用域返回一个数组,就可以避免在每次调用函数时为标识分配内存:
var a = [1,2,3];
function arr() {
return a;
}
如果您在不做任何看起来疯狂的事情时遇到JavaScript内存问题,那么您肯定正在动态创建函数。将所有函数提升到一个不需要重新创建它们的级别。正如您从上面可以看到的那样,仅函数的标识本身就非常庞大,考虑到大多数代码可以通过利用 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
参数。 看看为了什么而做了这么多工作。
与静态函数进行比较:
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;
}
.bind
每次都会返回一个新的函数,除非现在你还创建了一个上下文对象、一个 FixedArray 对象和大量其他垃圾(请参见 https://github.com/v8/v8/blob/ea835a25d9e53c7f1104f019b18fd0bfc69f1d3b/src/v8natives.js#L1727 和 https://github.com/v8/v8/blob/4d940b47fd46b1b4b1fcd50a2d34c74e1b320af4/src/runtime.cc#L8058)。如果您需要 bind 的功能,请使用自定义函数而不是内置函数:https://dev59.com/0WMk5IYBdhLWcg3w3xnq#18909668。 - Esailija