JavaScript中不同数据类型的内存使用情况

44

有一个问题困扰着我,那就是在JavaScript中不同的数据类型占用多少内存。例如,在C++中,int、char和float等数据类型使用2、1和8字节的内存顺序。那么在JavaScript中,Number、String、Boolean、Null、Undefined以及对象和数组等数据类型占用多少内存,以及被接受的范围是什么呢?请原谅我的英文水平低!


2
与 C 不同,在 JS 中,对于给定类型的值,没有特定的内存布局要求,这取决于 JS 引擎甚至是值的创建方式(例如,“字面字符串”与连接其他字符串)。这里的答案专注于有效载荷大小,这可能在不同对象之间共享,并且不包括对象本身的开销(请参见 https://dev59.com/_FcO5IYBdhLWcg3wcRJk#45808835 或 https://dev59.com/0HfZa4cB1Zd3GeqPOS7T#18975098 的示例)。 - Nickolay
3个回答

30

数字占用8个字节。

在这个w3schools页面找到了这个信息。

我再搜索了一些其他JavaScript原始类型的信息,但是惊讶的发现很难找到!不过我找到了下面的代码:

    ...
    if ( typeof value === 'boolean' ) {
        bytes += 4;
    }
    else if ( typeof value === 'string' ) {
        bytes += value.length * 2;
    }
    else if ( typeof value === 'number' ) {
        bytes += 8;
    }
    ...

似乎表明一个字符串每个字符占2个字节,而布尔值占4个字节。

在这里找到了这段代码和这里。完整的代码实际上是用来获取对象的大致大小。

虽然在进一步阅读时,我发现了这个有趣的代码,它来自于konijn 在这个页面: 计算字符串的字节长度

function getByteCount( s )
{
  var count = 0, stringLength = s.length, i;
  s = String( s || "" );
  for( i = 0 ; i < stringLength ; i++ )
  {
    var partCount = encodeURI( s[i] ).split("%").length;
    count += partCount==1?1:partCount-1;
  }
  return count;
}
getByteCount("i♥js"); // 6 bytes
getByteCount("abcd"); // 4 bytes

看起来字符串在内存中的大小取决于字符本身。虽然我仍在试图弄清楚为什么他把计数设置为1,如果是1,否则他在for循环中使用count-1

如果我发现其他任何内容,将更新帖子。


2
getByteCount 可以检测一个字符串的 URL 编码版本中有多少个 %,这个数字是 UTF-8 编码所需的字节数。这与内存中的表示无关。 - Rolf
6
4字节用于布尔类型?:D? - Adam
2
但是空字符串肯定不只占用0字节吧? - feihcsim

20
截至今日,MDN数据结构页面提供了更多相关信息:

数字

根据ECMAScript标准,只有一种数字类型:双精度64位二进制格式IEEE 754值。

因此应该为8个字节。

字符串

JavaScript的字符串类型用于表示文本数据。它是由16位无符号整数值的“元素”组成的集合。

因此每个字符应该为2个字节。

布尔值

布尔值表示逻辑实体,只能有两个值:true和false。

没有更多关于它的内容了。


1
问题:布尔类型的定义不也告诉你答案了吗?因为它只能是开或关,位要么是1/0,那么布尔值不应该是1位吗? - Kitanga Nday
18
不,一个比特能够存储布尔值并不意味着布尔值就只用一个比特来存储,因为涉及到内存管理和寻址技术等原因。在我学习计算机体系结构的时候,字节是最小可寻址内存单位。可以参考 这个 SO 问题 来获取答案。 - superjos
3
@KitangaNday,实际上一个布尔值使用4个字节存储,可以参考被接受的答案。 - Adam
@superjos 我在网络上发现了这个链接,我认为它可能回答了为什么布尔类型实际上占用4个字节的问题。 - Kitanga Nday
@KitangaNday 不确定它与JS有什么关系,它是关于C++的,特别是关于VS 4.2的“实现”,可以这么说。 - superjos
显示剩余3条评论

2

一个值的内存表示,也就是它的大小,除非另有规定,否则是一个实现细节,并且可以根据运行环境的底层代码而不同。运行时是运行JavaScript代码的应用程序,例如Nodejs、Firefox浏览器或Chrome浏览器。

假设你正在编写自己的运行时,并且想要表示一个布尔值。布尔值至少需要一个位,因此您可以将其存储在内存中作为单个位。

这是正确的:

这是错误的:

但是没有什么可以阻止您使用8位或一个字节的内存空间。这里最高有效位保存值,其余位将用0填充:

□□□□□□□■

或者64位:

□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■

同样的规则也适用于字符串值。您可以使用8位或64位甚至更多来表示它。然而,语言承诺在任何Unicode值上操作,但8位可能不足以表示所有Unicode值。这就是规范中一些寻址和调整的地方。在JavaScript中,字符串被视为UTF-16代码单元序列,并且某些字符占用16位内存空间,而其他字符占用32位。
代码单元是从Unicode规范借来的一个术语。你可能会问为什么不是字符而是代码单元,因为字符是表示特定文本数据的一种方式,还有其他方式。例如,é\u00E9\u{E9}都创建了带有重音符号的字母e。在JavaScript字符串中,您可以优先选择其中的任何一个。
数学很棘手,因为在CPU级别上,所有计算都是用二进制进行的,而二进制转换成十进制会出现问题。尝试运行0.1 + 0.1 == 0.3。因此,我们需要更严格的精度控制。这就是规范在数字表示上非常具体的原因:双精度64位二进制格式IEEE 754。
总之,在编写JavaScript运行时时,如何将值存储在内存中取决于您,除非在规范中明确规定。这就是为什么一些数据类型在如何表示和存储在内存中方面有很长的讨论的原因。
运行时环境通常是用低级语言编写的,例如C、C++或Rust,并且内存管理被委托给这些语言使用。
如果您是JavaScript程序员,则不需要担心内存如何分配和释放,因为运行时会为我们处理那部分。您可能唯一可能遇到的问题是通过循环引用导致的内存泄漏:对象A引用对象B,对象B引用对象A。开发者控制台中有工具可检测此类问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接