基本概念
栈(stack):是栈内存的简称,栈是自动分配相对固定大小的内存空间,并由系统自动释放,栈数据结构遵循FILO(first in last out)先进后出的原则,较为经典的就是乒乓球盒结构,先放进去的乒乓球只能最后取出来;
堆(heap):是堆内存的简称,堆是动态分配内存,内存大小不固定,也不会自动释放,堆数据结构是一种无序的树状结构,同时它还满足key-value键值对的存储方式;我们只用知道key名,就能通过key查找到对应的value。比较经典的就是书架存书的例子,我们知道书名,就可以找到对应的书籍;
特点:
栈的特点:开口向上、速度快,容量小;
堆的特点:速度稍慢、容量比较大;
栈和堆的联系
他们额联系就是 我们的 基础类型和引用类型的概念
基本数据类型:Undefined,String,Boolean,Null,Number,都是直接按值存放在栈内存中,占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说,更加容易管理内存空间。同时也用来保存基本值和引用类型值的地址
引用数据类型:指那些可能由多个值构成的对象,如对象(Object)、数组(Array)、函数(Function) ,它们是通过拷贝和new出来的,这样的数据存储于堆中。
在这里就引出了引用类型深浅拷贝的问题,拷贝的是 引用类型的地址 还是 它的真实值。
内存分配垃圾回收
1.内存分配:
(1)栈内存:线性有序存储,容量小,系统分配效率高。
(2)堆内存:首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中,效率相对就要低一些了。
2.垃圾回收:
(1)栈内存:变量基本上用完就回收了,相比于堆来说存取速度会快,并且栈内存中的数据是可以共享的。
(2)堆内存:堆内存中的对象不会随方法的结束而销毁,就算方法结束了,这个对象也可能会被其他引用变量所引用(参数传递)。创建对象是为了反复利用(因为对象的创建成本通常较大),这个对象将被保存到运行时数据区(也就是堆内存)。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。
局部变量和全局变量的销毁:
- 局部变量: 局部变量的生存依赖于其函数执行上下文环境中,函数执行完毕后,其局部变量也很容易被垃圾收集器作出判断并回收。
- 全局变量: 对于垃圾收集器而言,全局变量什么时候要回收是很难判断的。所以尽量少用全局变量,并且用完最好将其清空内存。
可能还是不太好理解,举个例子:
我们有一个函数 fn() 这个函数中有个变量 num,我们再函数外是没有办法拿到这个 num 的,就是因为他在函数结束就被销毁了
所有就有了 闭包(内存泄漏):
1.保存函数(父函数)调用栈(栈内存)。
另外闭包为了解决什么问题而产生呢?
之所以额外维护一个栈内存,是因为栈内存的变量不会与其他栈内存的变量名冲突,我们也称之为作用域。
普通函数寿命极短,因此作用域存活时间短;而闭包则是一个长期存活的函数作用域。
归根到底,
2.闭包是为了解决变量名冲突的问题。
另外插一嘴,为什么别人封装工具函数和模块,都使用闭包?
这和闭包的第一个作用有关。
如果不使用闭包,寿命极短,作用域创建即销毁,那么就是一个一次性工具。
使用闭包,它就能成为一个程序级别的工具,甚至是框架。