js中堆和栈的详解

堆和栈是数据存储的一种结构,因此我们首先从数据类型入手分析一下js数据存储的结构。

一、js的数据类型

为了更好容易的理解堆和栈,首先来复习一下js中的数据类型。在js中数据类型主要分为以下两大类:

基本类型: String,Number,Boolean,Null,Undefined,这5种基本数据类型它们是直接按值存放的,所以可以直接访问。
引用类型: Function,Array,Object,当我们需要访问这三种引用类型的值时,首先得从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

二、什么是堆什么是栈

其实了解过一些数据结构的同学应该都对堆和栈有一定的认识,堆栈不仅仅只有js中才有这个概念,不过这篇文章只针对js来进行描述。

栈(stack): 由操作系统自动分配内存空间,自动释放,存储的是基础变量以及一些对象的引用变量,占据固定大小的空间。
堆(heap): 由操作系统动态分配的内存,大小不定也不会自动释放,一般由程序员分配释放,也可由垃圾回收机制回收。

三、堆和栈的区别

1、栈:基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。(线性结构,后进先出)

优点:
(1)栈中的内容是操作系统自动创建、自动回收,占据固定大小的空间,因此内存可以及时得到回收,相对于堆来说,更加容易管理内存空间。
(2)相比于堆来说存取速度会快,并且栈内存中的数据是可以共享的,例如同时声明了var a = 1和var b =1,会先处理a,然后在栈中查找有没有值为1的地址,如果没有就开辟一个值为1的地址,然后a指向这个地址,当处理b时,因为值为1的地址已经开辟好了,所以b也会同样指向同一个地址。
缺点:
相比于堆来说的缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

2、堆:堆内存中的对象不会随方法的结束而销毁,就算方法结束了,这个对象也可能会被其他引用变量所引用(参数传递)。创建对象是为了反复利用(因为对象的创建成本通常较大),这个对象将被保存到运行时数据区(也就是堆内存)。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。

优点:
(1) 堆是操作系统动态分配的大小不定的内存,因此方便存储和开辟内存空间。
(2)堆中保存的对象不会自动释放,一般由程序员分配释放,也可由垃圾回收机制回收,因此生存周期比较灵活。
缺点:
相比于栈来说的缺点是,存在堆中的数据大小与生存期是不确定的,比较混乱,杂乱无章。

四、总结

1、按照JS的数据类型来说,基本数据类型(即值类型,包括:undefined、null、number、string、boolean、symbol)存在栈中,引用类型(即:object array function)存在堆中。

2、基本数据类型有固定的大小和值,存放在栈中,而引用类型不确定大小,但是其引用地址是固定的,因此,它的地址存在栈中,指向存储在堆中的对象。

3、基本数据类型,在当前环境执行结束时销毁,而引用类型只有在引用的它的变量不在时,会被垃圾回收机制回收。

4、复制方式不一样,值类型的是深复制(深拷贝),引用类型的是浅复制(浅拷贝),变量的复制其实是引用的传递。

5、值类型不可添加属性和方法,而引用类型可以添加属性和方法。

6、值类型比较相等,就可以用 == 或者 ===来比较,但是对于引用类型,即使let s = {};let s1 = {};但因为他们的内存地址不一样,比较结果依然不相等。

五、堆和栈的溢出

(1)如果想要堆溢出,比较简单,可以循环创建对象或大的对象;
(2)如果想要栈溢出,可以递归调用方法,这样随着栈深度的增加,JVM (虚拟机)维持着一条长长的方法调用轨迹,直到内存不够分配,产生栈溢出。

参考文献:
【1】https://blog.csdn.net/qq_33505829/article/details/86001203
【2】https://www.jianshu.com/p/3541b98c786e

发布了33 篇原创文章 · 获赞 35 · 访问量 812

猜你喜欢

转载自blog.csdn.net/chaopingyao/article/details/105022761