因为JavaScript具有自动垃圾回收机制,内存空间并不是一个经常被提及的概念。JavaScript中的内存分为栈内存与堆内存
JavaScript中的变量的存放有原始值和引用值之分。原始值代表了原始的数据类型(基本类型),如:undefined,null,string,number,boolean类型的值;引用值代表了引用的数据类型(引用类型),如:Object,Function,Array,RegExp.
一、栈与堆
Javascript中的内存分为栈内存与堆内存。一般来说,栈内存中存放的是存储对象的地址,而堆内存中存放的是存储对象的具体内容
对于原始类型的值而言,其地址和具体内容都存在与栈内存中;而基于引用类型的值,其地址存在栈内存,其具体内容存在堆内存中
栈内存与堆内存的区别
栈内存空间相对堆内存来说比较小,运行效率比堆内存高,内存空间释放也比堆内存快。反之则是堆内存的特点。所以将构造简单的原始类型值放在栈内存中,将构造复杂的引用类型值放在堆中而不影响栈的效率。
(1)栈内存,存放数据叫压栈(进栈),读取数据是出栈。特点:先进后出,后进先出:。下图表明了栈空间的存储原理:
(2)堆内存的存取数据的方式,则与书架与书非常相似。书虽然也整齐的存放在书架上,但是我们只要知道数的名字,我们就可以很方便的取出我们想要的书,而不用像从乒乓球盒子里取乒乓一样,非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中,我们存储的key-value是可以无序的,因为顺序的不同并不影响我们的使用,我们只需要关心书的名字。
栈内存和堆内存的存取
JavaScript不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。
当我们要访问堆内存中的引用数据类型时,实际上我们首先是从变量对象中获取了该对象的地址引用(或者地址指针),然后再从堆内存中取得我们需要的数据。
常见面试题
在变量对象中的数据发生复制行为时,系统会自动为新的变量分配一个新的值。var b=a 执行之后,a与b的值虽然都等于20,但是他们其实已经是相互独立互不影响的值了,所以修改了b的值以后,a的值并不会发生变化。
通过 var n=m 执行一次复制引用类型的操作。引用类型的复制同样也会为新的变量自动分配一个新的值保存在变量对象中,但不同的是,这个新的值,仅仅只是引用类型的一个地址指针。当地址指针相同时,尽管它们相互独立,但是在变量对象中访问到的具体对象实际上是同一个。因此当改变n时,m也发生了变化。这就是引用类型的特性。
二、内存空间管理
因为JavaScript具有自动垃圾收集机制,所以我们在开发时好像不用关心内存的使用问题,内存的分配与回收都完全实现了自动管理。了解内存机制有助于自己清晰的认识到自己写的代码在执行过程中发生过什么,从而写出性能更加优秀的代码。因此关心内存是一件非常重要的事情。
JavaScript的内存生命周期
1、分配你所需要的内存
2、使用分配到的内存(读、写)
3、不需要时将其释放、归还
JavaScript有自动垃圾收集机制。这个自动垃圾收集机制的原理是:找出那些不再继续使用的值,然后释放其占用的内存。垃圾收集器会每隔固定的时间段就执行一次释放操作。
在JavaScript中,最常用的是通过标记清除的算法来找到哪些对象是不再继续使用的,因此a=null其实仅仅只是做了一个释放引用的操作,让a原本对应的值失去引用,脱离执行环境,这个值会在下一次垃圾收集器执行操作时被找到并释放。而在适当的时候解除引用,是为页面获得更好性能的一个重要的方式。