JS中的堆和栈及内存泄漏

一、栈

从电脑内存中分配一块出来,用来执行代码的内存,Stack
先创建变量,再做赋值操作分配一个主线程来自上而下执行。(js单线程,浏览器多线程)主要用来运行代码,和存储基本类型。

1.基本数据类型储存

  1. 变量存储空间,存创建的变量
  2. 值存储空间,存基本数据类型的值
  3. 一个值存储空间可以对应多个变量,
    一个变量只能对应一个值存储空间。

2.说明
栈内存:是一个执行代码的一个空间,这个调用栈只有一个,并且大小固定,按照一定的排列规则自上而下,顺序执行。通俗点说就是先进后出

3.堆栈溢出
溢出:因为栈内存空间有限,当你执行一些递归操作没有阻断或者释放的时候,反复调用,栈内存执行序列就会排不下了。

二、堆

  1. 从内存中有拿出来一块,用来存引用数据类型
    Heap,一个16进制的地址。
  2. 按照键、值分别存放,并关联起来

打印java堆栈信息 js打印堆栈信息_存储空间


引用数据类型存储

堆内存不是有个地址么,放到栈内存的值存储空间,并和变量关联

三、深拷贝和浅拷贝

简单的说,浅拷贝就是只将对象 最外层 的键值复制为一个新的对象,而深拷贝则会 递归复制所有的层 ,直到该键的值为基本类型值。 再简单点说 ,经过浅拷贝后,新旧变量可能还会有所关联(既然说了是可能还有所关联,那也可能毫无关联吧,这里的关键就在于原对象的复杂程度了);而经过深拷贝后,理论上,新旧变量再无关联。 注意 ,在进行深拷贝时,层级不宜过多。所以,一般的深拷贝也并不是绝对毫无关联的。

var obj = {
a: "a is a",
arr: [ 1, 2, 3]
}, obj1 = { ...obj }, //假装这里是个浅拷贝
obj2 = JSON.parse(JSON.stringify(obj)); //假装这里是深拷贝。
obj1.a = "value a";
obj1.arr[0] = 66;

打印java堆栈信息 js打印堆栈信息_存储空间_02


可以看到,当原对象的值为 基本类型值 时,浅拷贝和深拷贝并没有区别;而当原对象的某些值为 引用类型值 时,如果修改变量的值,浅拷贝会改变原对象的值,而深拷贝则不会。

四、垃圾回收

现在浏览器基本都在使用标记-清除的算法来执行垃圾回收。而不是使用引用计数的方式,因为引用计数方式无法释放循环引用结构的内存占用。 标记清除算法的核型概念是:从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的。那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。

五、内存泄露

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。 对于不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)

常见的内存泄露
1. 不合理的计时器
		 2. 被共享的闭包作用域
		 3. 脱离dom引用
		 4. 意外的全局变量