likes
comments
collection
share

JavaScript堆内存and栈内存

作者站长头像
站长
· 阅读数 54

背景

在面试或者在技术群里经常遇到同学们讨论一个问题:Javascript的内存分配是怎么样的,什么数据放在栈内存,什么数据放在堆内存?

关于这个问题有两种说法:

  • 阵营一:原始值或者说是基本类型的值保存在栈内存中,引用数据类型保存在堆内存中
  • 阵营二:部分Number类型保存在栈内存中,其他数据都保存在堆内存中

我本人站第二种说法

Javascript到底是怎样分配内存的呢?今天就带大家扒一扒两种阵营的说法到底是怎么来的

阵营一:原始值保存在栈内存,引用数据类型保存在堆内存

  • 知乎一篇文章(转自:博客园)

JavaScript堆内存and栈内存

JavaScript堆内存and栈内存

JavaScript堆内存and栈内存

JavaScript堆内存and栈内存

  • 《Javascript高级程序设计》(4.4章节小结)

JavaScript堆内存and栈内存

  • 极客时间:浏览器工作原理与实践(12 | 栈空间和堆空间:数据是如何存储的?)

JavaScript堆内存and栈内存

阵营二:部分Number类型保存在栈内存中,其他数据都保存在堆内存中

参考资料

首先要知道,JavaScript的标准ECMA-262并没有定义内存分类,其完全依赖编译器如何实现。这里我们以V8为讨论对象

根据官方博客文章Pointer Compression in V8原文,V8中的JavaScript值无论是object, array, number还是string都作为对象分配到V8 heap也就是堆内存中

JavaScript堆内存and栈内存

这里并没有结束,虽然说全部值都保存在堆内存中,但是考虑到大部分程序需要进行整形数值的计算,V8采用标记指针技术可以将small integer直接存储在本应存储指针的位置。在32/64位系统中,都使用最后一位来标记当前位置是small integer还是指针

JavaScript堆内存and栈内存

JavaScript堆内存and栈内存

另外Chrome开发者文档的文章Memory terminology中也指出Number数据类型会被分为两种,31位的small integer和另外一种heap number,证明了small integerSMI存储在栈中,其他Number数据存储在堆中,同时该文章也明确指出string存储在VM Heap也就是堆中

JavaScript堆内存and栈内存

两篇官方文档指明了:string类型会保存在堆中,并不是原始类型都保存在栈中。除了SMI,其他数据都保存在堆中

总结

针对阵营一的观点搜集到的文章,排除掉没有参考资料转自其他文章这些人云亦云缺乏思考的,比较权威的就是《Javascript高级程序设计》,其中一些文章也是引自这本书的结论。这本书的结论从何得来,并没有更根源的参考依据或者更详细的论证

极客时间的课程中,作者并没有给出详细论证和更权威的参考资料,另外对于同学的问题作者也并没有给出回答

JavaScript堆内存and栈内存

对于阵营一这个观点的疑问有:

  • 字符串占用的空间并不是固定大小,但却是基本数据类型,也会保存在栈中吗?
  • 并没有官方资料或者其他权威资料给与佐证

对于阵营二的观点,有V8官方博客和Chrome官方文章作为论证,同时也解答了针对阵营一的"字符串是否保存在栈中"的疑问(结论:保存在堆中)

另外阵营二的讨论中参考的知乎回答也有详细的步骤,通过开发者工具对内存进行分析进行佐证,甚至分析了V8的源码

结论个人站队阵营二的观点,有不同意见的同学,也希望能在评论区赐教!

关于堆和栈

大部分文章还有一个误区:会拿数据结构的堆来和内存堆讨论

其实堆栈的概念是用于传统系统语言C,C++等,个人认为JavaScript并没有栈的概念,如上文引用的官方博客Pointer Compression in V8或者Orinoco: young generation garbage collection中说明,JavaScript的对象都保存在VM Heap中,官方博文也并没有出现过栈内存的概念。只是由于V8大部分使用C++进行开发,可以理解为JavaScript的指针数据会保存在C++的栈内存中,所以会有针对JavaScript的堆栈内存的讨论

Stack是向下增长一块内存区域,栈区同数据结构的栈相同先进后出。栈区空间较小分配效率高,系统会自动进行分配和空间回收

Heap和数据结构的堆就没有关系了,堆被用于动态内存分配。程序开发者使用mallocnew申请任意大小的内存,用freedelete释放内存。动态内存的生存期可以由我们决定。堆是一块向上增长的内存区域。V8中的堆被分为新生代区和老生代区等,这个是垃圾回收的问题,不在本文讨论

感悟

这篇文章主要是希望能给大家提供一个辩证看待问题的思路,在对待深层次的理论问题,能去多考究官方权威资料,而不是人云亦云。虽然这种问题属于面试造火箭的范畴,实际工作中几乎用不到,但是在面试中如果不仅能给出一个问题的答案,而且能回答出研究问题的思路,体现出对待问题认真深入的态度,也能给面试官留下一个好印象,为面试加分

最后,希望大家能从本篇文章中有所收获,欢迎有不同思路意见的大佬评论区留言讨论!

转载自:https://juejin.cn/post/7195231830272901179
评论
请登录