内存管理以及闭包概念

89 阅读3分钟

认识内存

  • 不管什么样的编程语言 在代码的执行过程都需要给它分配内存的 不同的是有些语言是需要手动分配 有些语言是需要自动分配
  • 内存的管理也有他自己的生命周期
    1. 分配你申请的内存
    2. 使用你分配的内存(存放一些东西,比如对象等)
    3. 不需要使用时候,将其释放

在js中内存的分配

space.jpg 如果是基础数据类型,会在栈空间里面(表达式赋值) 如果是数据类型内存分类(函数),会在堆空间 里面创建一个内存空间 有个内存地址 let obj = (0ax00(内存地址))

js的垃圾回收

因为内存的大小是有限的 当我们的内存不再需要的时候 我们将需要给他内存释放出来 以便腾出更多的内存空间 如果手动回收内存的话 会有两个限制

  1. 会影响逻辑的代码效率
  2. 对开发者的要求也很高 一不小心就会造成内存泄漏 js引擎有自己的垃圾回收器 会自动回收内存 英文名是Garbage Collection 简称GC GC它有自己本身的一个算法(如何回收垃圾?如何判断是不是垃圾) 垃圾回收也会定时从 根对象开始找引用对象,看是否可以找到

GC算法:每一个内存空间他都有一个retain count 一个计数着 引用该空间的数量 当它为0的时候 代表着这个空间可以被回收 info.friend=null 这样它的retain count 就会减1

闭包

闭包的概念

js中函数是一等公民(可以作为参数 返回值)

维基百科中对闭包的解释

  1. 他是在支持头等函数的编程语言中 实现**词法绑定(也就是在编译代码期间的parse阶段)**的一种技术
  2. 闭包实际上就是一个结构体(对象),它储存了一个函数和一个关联环境(也就是作用域链的自由变量)(相当于一个符号查询表)
  3. 闭包跟函数最大的区别在于 当捕获闭包的时候 它的自由变量(在词法分析中)会在捕捉时确认,这样即使脱离了捕捉时的上下问 也能照常运行

在MDN中对闭包的解释

  1. 一个函数和对其周围状态(词法状态)的引用捆绑一起(函数被引用包围)
  2. 闭包可以让你在一个内层函数中访问到外层函数的作用域(父级作用域AO)
  3. 在js中 每当创建一个函数,闭包就会在函数创建出来

从一幅内存图中来看

closure-h-01.png 这个图所表示在编译期间 GO里main保存着makeAdder所指向的内存地址 和add10所指向的内存地址 在执行代码期间 makeAdder的时候 它的AO就是0x200的参数(这个AO是会被保留下来的) 当makeAdder执行一个函数 这个时候会再创建一个新的内存空间 0xb00 它的作用域链是0x200 加上自己的AO 所以第一次makeAdder执行完了被弹出执行上下文栈 但是它的参数会一直被保留 因为0xb00会引用这个参数。等add=null makeAdder=null 的时候 它的内存空间被销毁 它就不会有再有指向 最后被GC给回收掉

总结

闭包是由两部分组成的:函数+可以访问的自由变量 闭包的原因就是当函数在执行完 在执行栈中被销毁 但是在全局go中依旧还有指向的内存空间 导致这些内存无法被释放 所以当函数不使用的时候 需要将**fn=null **也就是把fn在全局GO中的空间指针指到0x0 也就是一个空的内存空间