理解JS内存空间及变量存放

238 阅读5分钟

内存空间管理

JavaScript的内存生命周期是

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时将其释放、归还

JavaScript有自动垃圾收集机制,最常用的是通过标记清除的算法来找到哪些对象是不再继续使用的,使用a = null其实仅仅只是做了一个释放引用的操作,让 a 原本对应的值失去引用,脱离执行环境,这个值会在下一次垃圾收集器执行操作时被找到并释放。

在局部作用域中,当函数执行完毕,局部变量也就没有存在的必要了,因此垃圾收集器很容易做出判断并回收。但是全局变量什么时候需要自动释放内存空间则很难判断,因此在开发中,需要尽量避免使用全局变量

在JS中,每一个数据都需要一个内存空间。内存空间又被分为两种,栈内存(stack)与堆内存(heap)

栈(stack)

栈的结构就是后进先出。这里使用乒乓球盒子的结构来理解一下:

处于盒子中最顶层的乒乓球5,它一定是最后被放进去,但可以最先被使用。而我们想要使用底层的乒乓球1,就必须将上面的4个乒乓球取出来,让乒乓球1处于盒子顶层。

image

堆(heap)

堆数据结构是一种树状结构。它的存取数据的方式与书架和书非常相似。只需要知道书的名字就可以直接取出书了,并不需要把上面的书取出来。JSON格式的数据中,存储的key-value可以是无序的,因为顺序的不同并不影响使用,只需要关心书的名字。

变量存放

  • 基本类型 --> 保存在栈内存中,因为这些类型在内存中分别占有固定大小的空间,通过按值来访问。
  • 引用类型 --> 保存在堆内存中,因为这种值的大小不固定,因此不能把它们保存到栈内存中,但内存地址大小的固定的,因此保存在栈内存中,在栈内存中存放的只是该对象的访问地址。当查询引用类型的变量时, 先从栈中读取内存地址,然后再通过地址找到堆中的值。 对于这种,我们把它叫做按引用访问。

通过代码和示意图更好的去理解:

//原始类型都放在栈(stack)里
//引用类型都放在堆(heap)里
var a = 10;
var b = 'lzm';
var c = true;
var d = { n: 22 }; //地址假设为0x0012ff7f,不代表实际地址
var e = { n: 22 }; //重新开辟一段内存空间,地址假设为0x0012ff8c
console.log(e==d); //false
var obj = new Object(); //地址假设为0x0012ff9d
var arr = ['a','b','c']; //地址假设为0x0012ff6e

image

在计算机的数据结构中,栈比堆的运算速度快,Object是一个复杂的结构且可以扩展:数组可扩充,对象可添加属性,都可以增删改查。将他们放在堆中是为了不影响栈的效率。而是通过引用的方式查找到堆中的实际对象再进行操作,所以查找引用类型值的时候先去栈查找再去堆查找。

几个问题

问题1

var a = 1;
var b = a;
b = 2;

// 这时a的值是多少?

image

上图中可以看出,答案为:1。在栈内存中的数据发生复制行为时,系统会自动为新的变量分配一个新值。var b = a执行之后,a与b虽然值都等于1,但是它们其实已经是相互独立互不影响的值了。

问题2

var a = {name: 'a'} 
var b = a 
b.name = 'b' 

// 现在 a.name 是多少?

image

上图中可以看出,答案为:"b"。我们通过var b = a执行一次复制引用类型的操作。引用类型的复制同样也会为新的变量自动分配一个新的值保存在栈内存中,但不同的是,这个新的值,仅仅只是引用类型的一个地址指针。当地址指针相同时,尽管他们相互独立,但是在堆内存中访问到的具体对象实际上是同一个,因此b.name ='b'使堆内存中对象的value值变化,a.name的值也随之变化。

问题3

var a = {name: 'a'} 
var b = a 
b = null 
请问现在 a 是什么

image

上图中可以看出,答案为:{name:"a"}。因为null为基本类型,存在栈内存当中。因此栈内存中的变量b由之前指向对象的一个地址转变为null,变量a的地址还是指向原先的对象。

总结

栈内存堆内存
存储基本数据类型存储引用数据类型/或基础数据类型,如闭包中的数据
按值访问按引用访问
存储的值大小固定存储的值大小不定,可动态调整
由系统自动分配内存空间由程序员通过代码进行分配
主要用来执行程序主要用来存放对象
空间小,运行效率高空间大,但运行效率相对较低
后进先出无序存储,可根据引用直接获取

参考:
juejin.cn/post/684490…
muyiy.cn/blog/1/1.3.…