栈内存和堆内存区别
一、栈内存
1、在js中栈内存用来存储基本类型
和引用类型的指针
,
堆内存用来存储引用类型
。
2、栈(stack)会自动分配内存空间
,栈内存变量基本上用完就会自动释放
。
堆(heap)动态分配的内存,大小不定
也不会自动释放
,只有当所有调用的变量全部销毁
之后才能回收
3、栈内存线性有序存储,容量小,系统分配效率高
。
而堆内存首先要在堆内存新分配存储区域
,之后又要把指针存储到栈内存中
,效率相对就要低一些
4、栈内存主要用于存储各种基本类型的变量
,
堆内存主要负责像对象Object这种变量类型
的存储
二、垃圾回收机制
内存中某个空间地址中的数据,没有变量或者标识符
,那么这个内存空间就会在下一次垃圾回收机制执行的时候被释放
三、JavaScript内存管理
其实JavaScript内存的流程很简单,分为3步:
1、分配给使用者所需的内存
2、使用者拿到这些内存,并使用内存
3、使用者不需要这些内存了,释放并归还给系统
那么这些使用者
是谁呢?举个例子:
var num = ''
var str = '张三'
var obj = { name: '张三' }
obj = { name: '张三2' }
上面这些num,str,obj就是就是使用者
,我们都知道,JavaScript数据类型分为基础数据类型
和引用数据类型
:
基础数据类型:拥有固定的大小,值保存在栈内存里,可以通过值直接访问
引用数据类型:大小不固定(可以加属性),栈内存中存着指针,指向堆内存中的对象空间,通过引用来访问
由于栈内存
所存的基础数据类型大小是固定的,所以栈内存的内存都是操作系统自动分配和释放回收的
由于堆内存
所存大小不固定,系统无法自动释放回收
,所以需要JS引擎来手动释放这些内存
四、基本数据类型和引用数据类型的区别
基本数据类型中的变量都是保存在栈内存中的,值与值之间相互独立
,修改一个变量是不会改变另一个变量的值
var a = 10
var b = a
a = 20
console.log('a,b', a,b) //a,b 20 10
引用数据类型保存在堆内存中,每创建一个引用对象
,就会在堆内存中开辟一个新的空间
,而栈内存中
的主要保存的是引用数据类型的内存地址(指针)
可以理解为通过任意一个标识符对其内部数据进行修改都会影响后续其他同样指向这个引用类型数据访问的结果
var obj1 = {
name:'张三'
}
//变量赋值给变量 访问的是同一个数据的内存空间地址
var obj2 = obj1
obj1.name = 'ikun'
console.log('obj1.name', obj1.name) //ikun
console.log('obj2.name', obj2.name) //ikun
当obj1的name值改变时,obj2的name值也随之改变,
因为引用数据类型保存的是地址值,obj1和obj2 地址值是一样的,指向同一个堆内存
五、思考
5.1、为什么const定义的值部分能改,部分不能改?
当我们const定义一个对象
的时候, 我们说的常量其实是指针
,就是const对象对应的堆内存指向是不变的
,但是堆内存中的数据本身的大小或者属性
是可变的`。
而对于const定义的基础变量而言,这个值就相当于const对象的指针,是不可变
5.2、为什么const、let定义的变量不能二次定义
每次使用const或者let去初始化一个变量的时候,会首先遍历当前的内存栈,看看有没有重名变量,有的话就返回错误
5.3、new关键字初始化的之后是不是存储在栈内存中
let str1 = new String('123')
let str2 = new String('123')
console.log(str1==str2, str1===str2) // false false
很明显,如果str1 ,str2 是存储在栈内存中的话,两者应该是明显相等的,但结果两者并不相等,说明两者都是存储在堆内存中的,指针指向不一致
。