V8/Node.js中数组存字符串、对象属性赋值时是否复制字符串?
在V8/Node.js中原始类型推入数组或赋值给对象属性的内存机制
核心结论
在V8/Node.js环境中,字符串、数字、布尔这类原始类型(注:V8中字符串是不可变对象,但表现出原始类型特性),当推入数组或赋值给对象属性时,不会复制字符串/原始值的内容,而是复用指向内存中同一实例的引用。
逐一解释你的示例场景
1. 重新赋值变量不影响数组内容的原因
let array = [] let x = 'foo' array.push(x) x = 'bar' console.log(array) //=> ['foo']
这里的“值传递”是指将x持有的引用(指向'foo'字符串实例)复制给数组元素。当你把x重新赋值为'bar'时,只是改变了x变量自身的引用指向,数组元素仍保留着指向原'foo'实例的引用,因此数组内容不受影响。这并不代表数组存储了'foo'的内容副本。
2. 多次推入同一字符串不会重复占用内存
let array = [] let x = 'foo' array.push(x) array.push(x) array.push(x)
V8内置**字符串驻留(String Interning)**优化:相同的字符串字面量会被存储在内存中的同一个实例里。无论你将x推入数组多少次,数组的每个元素都是指向同一个'foo'实例的引用,内存中只会保留一份'foo'的内容,不会因多次推入增加字符串本身的内存开销。
3. 同一字符串赋值给多个对象属性同理
let object = {} let x = 'foo' object.a = x object.b = x object.c = x
和数组场景完全一致:object.a、object.b、object.c均指向同一个'foo'字符串实例,内存中仅存在一份'foo'的内容,不会因多属性赋值复制字符串内容。
对你的内存计算需求的建议
如果你用Buffer.byteLength(text, 'utf8')计算字典树的大致内存占用,只需统计每个唯一字符串的长度即可。重复的引用不会带来额外的字符串内容内存开销,无需累加每个引用对应的字符串长度。
纠正错误说法
所谓“内置原始类型推入数组时是复制”的表述不准确——这里的“复制”仅指复制引用,而非复制字符串的实际内容。V8的字符串驻留机制确保了相同字符串的内存复用,不会产生内容副本。
内容的提问来源于stack exchange,提问作者Lance Pollard
相关产品推荐
相关产品推荐

