JavaScript原始类型(Primitives)与内存分配机制相关疑问咨询
JavaScript原始类型内存分配问题解答
ECMAScript 规范本身没有对原始值的内存分配逻辑做强制规定,所有实现只要符合「原始值不可变、按值比较/传递」的语义即可,网络上的矛盾内容大多是混淆了不同JS引擎的实现差异,或是把特定场景的优化逻辑当成了通用规则。
1. 原始值的存储位置
原始值的存储分为两种主流实现逻辑,由JS引擎根据值的类型、大小自动选择:
- 小尺寸的高频原始值(比如V8引擎中范围在-230到230-1的小整数、短字符串、布尔值、null、undefined)会直接存在执行栈的变量槽中,不存在引用的概念。变量对应的栈内存位置存的就是原始值本身,不是指向其他内存的指针。
- 大尺寸原始值(比如超长字符串、超出小整数范围的BigInt等)会存储在堆内存中,变量槽里存储指向堆内存的引用。为了节省内存,引擎会对这类值做内部驻留优化:相同值只会在堆里存一份,多个变量的引用都指向同一个地址。
2. 示例代码的实际运行逻辑
以V8引擎的实现为例:
const x = 1; let y = x; y = 2;
这里的1和2都属于小整数,全程不会涉及堆分配和引用:
- 第一行执行时,直接在栈中给x分配的变量槽里写入值1
- 第二行执行时,直接把x槽位里的1拷贝到y对应的栈槽里,是两个完全独立的值,不存在两个引用指向同一个1的情况
- 第三行执行时,直接把y的栈槽内容修改为2,完全不会影响x的存储内容
这个逻辑也完全符合原始值的不可变语义:你修改的只是变量存储的内容,从来没有修改过1或者2本身的值。
3. 原始值是否会在整个执行周期共用同一个内存地址
这完全取决于引擎的优化策略,没有统一标准:
- 对于已经做了内部驻留的原始值,比如常用小整数、代码里字面量声明的短字符串,整个执行周期内只要是相同的值,都会指向同一个内存地址
- 对于动态生成的原始值(比如运行时拼接得到的字符串、运算得到的大整数),如果引擎没有即时做驻留处理,可能会出现两个值完全相等,但底层存储地址不同的情况。不过你完全感知不到这个差异,因为规范要求原始值的比较是按值判断,不会对比内存地址。
内容的提问来源于stack exchange,提问作者Agustín Vazquez
相关产品推荐
相关产品推荐

