前端内存空间理解

var a = 20;
var b = 'abc';
var c = true;
var d = { m: 20 }

在学习内存空间之前,我们需要对三种数据结构有一个直观的认知。他们分别是堆(heap),栈(stack)与队列(queue)。

一、栈数据结构

要简单理解栈的存取方式,我们可以通过类比乒乓球盒子来分析。如下图所示。

这种乒乓球的存放方式与栈中存取数据的方式如出一辙。处于盒子中最顶层的乒乓球5,它一定是最后被放进去,但可以最先被使用。而我们想要使用底层的乒乓球1,就必须将上面的4个乒乓球取出来,让乒乓球1处于盒子顶层。这就是栈空间 先进后出,后进先出的特点。图中已经详细的表明了栈空间的存储原理。

二、堆数据结构

堆数据是一种树状结构。它存储数据的方式与书架和书非常相似。
书放在书架上,我们只需要知道书的名字就可以找到我们想要的书。好比在Json格式的数据中,我们存储的key-value是可以无序的。我们只需关心书的名字。

三、队列

队列是一种先进先出(FIFO)的数据结构。正如排队过安检一样,排在队伍前面的人一定是最先过检的人。用以下的图示可以清楚的理解队列的原理。

四、引用数据类型与堆内存

其他语言不同,JS的引用数据类型,比如数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以理解为保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。
var a1 = 0;   // 变量对象
var a2 = 'this is string'; // 变量对象
var a3 = null; // 变量对象

var b = { m: 20 }; // 变量b存在于变量对象中,{m: 20} 作为对象存在于堆内存中
var c = [1, 2, 3]; // 变量c存在于变量对象中,[1, 2, 3] 作为对象存在于堆内存中

因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从变量对象中获取了该对象的地址引用(或者地址指针),然后再从堆内存中取得我们需要的数据。

两个列子

var a = 20;
var b = a;
b = 30;

// 这时a的值是多少?

var m = { a: 10, b: 20 }
var n = m;
n.a = 15;

// 这时m.a的值是多少

我们通过var n = m执行一次复制引用类型的操作。引用类型的复制同样也会为新的变量自动分配一个新的值保存在变量对象中,但不同的是,这个新的值,仅仅只是引用类型的一个地址指针。当地址指针相同时,尽管他们相互独立,但是在变量对象中访问到的具体对象实际上是同一个。如图所示。

因此当我改变n时,m也发生了变化。这就是引用类型的特性。

五、内存空间管理

因为JavaScript具有自动垃圾收集机制,所以我们在开发时好像不用关心内存的使用问题,内存的分配与回收都完全实现了自动管理。但是根据我自己的开发经验,了解内存机制有助于自己清晰的认识到自己写的代码在执行过程中发生过什么,从而写出性能更加优秀的代码。因此关心内存是一件非常重要的事情。

1. 分配你所需要的内存

2. 使用分配到的内存(读、写)

3. 不需要时将其释放、归还

var a = 20;  // 在内存中给数值变量分配空间
alert(a + 100);  // 使用内存
a = null; // 使用完毕之后,释放内存空间

javascript有自动垃圾回收机制,原理:就是找出那些不再继续使用的值,然后释放其占用的内存。垃圾收集器会每隔一段时间就执行一次释放操作。

在javascript中,最常用的是通过标记清除的算法来找到哪些对象是不再继续使用的,因此a=null其实仅仅只是做了一个释放的操作,让a原本对应的值失去引用,脱离执行环境,这个值会再下一次垃圾收集器执行操作时被找到并释放。而在适当的时候解除引用,是为页面获得更好的性能的一个重要的方式。

原文链接:https://www.jianshu.com/p/996671d4dcc4

猜你喜欢

转载自www.cnblogs.com/ts1996/p/10303661.html