在JS中具有自动垃圾回收机制,对于前端开发来说,内存空间并不是被常常提起的概念,容易被大家忽视。很多东西的原理与内存息息相关,如:闭包、深签拷贝、执行上下文等,要弄清楚这些,必须对内存空间有清晰的认知才行。
堆栈段
栈:栈会自动分配内存空间,会自动释放内存,存放基本类型,占据固定大小的空间。
堆:动态分配的内存,大小不定也不会自动释放内存,存放的是引用数据类型。
栈的存取方式,先进后出,后进先出。可以想象成一个盒子,并且只有一个出口和入库,如图a2在栈低,肯定是最先进入盒子的,然后再试a3、a4、a5。那么在盒子中a5在最上面,也是最先出来的,如果想要a2出来那么必须先拿出来a5,其次a4、a3,最后才是a2。内存中栈空间就是这么个存储原理。
堆空间可以比喻成书架,我们只需要知道书的名字,就可在书架上找到那本书。和栈空间相比,就不用拿能某一个球,必须把上面的球全部拿出来。堆空间中就从顺序来说,就显得不那么重要。
堆栈段中存放数据
在栈空间中保存的是基础数据类型,number、string、boolean、undefined、null、symbol。而在堆空间中保存的是引用数据类型,array、object。js不允许直接访问堆空间中的位置,所以不能直接去操作对象的堆内存空间。那么在操作对象时,实际上是在操作对象的引用,而不是实际的对象。引用就相当于一个地址(上个例子的“书名”)
let a = 1;
let b = 'str'
let c = { name: '张三' }
let d = [1, 2, 3, 4]
我们可以看到c、d保存的是一个引用(相当于地址),当我们去访问c、d的值,首先访问的是该对象或数据的内存地址,然后在从堆空间中取的我们想要数据。
这里有个小例子
let a = 10;
let b = a;
b = 20;
console.log(a);//10
let c = { name: '张三', age: 20 }
let d = c
d.age = 30;
console.log(c.age);//30
在数据发生复制行为时,系统会自动为新的变量分配一个新值。当a = b时虽然值相同,但是已经都是独立的个体了,互不影响。当d = c时,是把一个对象复制给它,其实复制的是一个引用地址。虽然名字不同,但是保存的都是同一个引用地址。修改其中一个,对应的数据也会修改。
内存空间管理
因为JS有自动垃圾回收机制,内存的分配与回收都完全实现了自动管理
JS的内存生命周期:
1、分配你所需要的内存
2、使用分配到的内存(读、写)
3、不需要时将其内存释放。
// 在内存中分配空间
let a = { name: '张三', age: 20 }
// 修改
a.age = 30;
a.name = '李四';
// 使用完后,释放内存
a = null;
JS有自动垃圾回收机制,原理是,找出不在继续使用的值,然后释放占用的内存。垃圾收集器会每隔固定时间段就执行一次释放操作。
在JS中,最常用的是通过标记清除的算法来找到那些数据是不在使用的,a = null其实仅仅是做了一个释放引用的操作,让a原本对应的值失去引用,脱离执行环境,这个值会在下一次垃圾收集器执行操作时被找到并释放。而在适当的时候解除引用,是提升性能的一个方式。
如果一个值不再需要了,引用数却不为0,垃圾回收机制是无法释放这块内存,从而导致 内存泄漏
(如:不正确的使用闭包)