JavaScript 类型的内存分配

Memory allocation for JavaScript types

本文关键字:分配 内存 类型 JavaScript      更新时间:2023-09-26

我正在尝试优化我正在开发的移动应用程序,我想知道什么占用最小的内存(我意识到这可能因浏览器而异):

  • 对象指针
  • 布尔文字
  • 数字文字
  • 字符串

理论上哪个应该占用最少的内存空间?

在 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;
}

简单得多。

如果你在 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.看看白白做了多少工作。

与静态函数比较:

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;
}
"

Literal"表示代码(即使不是在字符串序列化中),这是一个更复杂的类型,因此比花费更多的空间。

从理论上讲,布尔值可能占用的空间最少,因为它们适合单个位。尽管任何引擎都不太可能对此进行优化。如果要强制执行此操作,可以手动执行此操作并使用类型化数组。

但是,性能是实际的东西,你只能测试,测试,测试它。如您所知,没有明确的跨浏览器跨版本答案。