JS内存管理
内存原理:
任何变成语言在执行的时候都需要操作系统来分配内存,只是有些语言需要手动管理分配的内存有些语言有专门来管理内存的方式 如 JVM
了解以上的概念之后,我们再来了解一下大致的内存周期
- 分配需要的内存
- 使用内存
- 在不使用的时候释放内存
JS 属于自动管理内存的语言
在我们定义数据的时候 JS 会给我们分配内存,但是内存分配的方式有区别
- 对于原始数据内存分配在执行的时候 直接放在栈空间进行分配
- 对于复杂的数据类型 会在堆内存中开辟一块空间 并且将这块空间的指针返回值变量引用
垃圾回收机制算法
概念:
因为内存的大小是有限的,所以当内存不再需要的时候,我们需要对其进行释放,以便腾出更多的内存空间。
对比手动管理内存释放语言 对于开发者的技术要求非常高,一旦操作不但 效果反而会变得很差,这个也形成了高手可以做到性能很高 但是苦于进阶的选手,所以现在大部分高级语言都实现了GC也就是垃圾回收机制/垃圾回收算法
GC怎么知道哪些对象是不再使用的呢?
对于GC的实现是百花齐放的 设计语言的人总能整出花活,这里介绍几个常见的GC算法
常见GC - 引用计数(Reference counting)
- 当一个对象有一个引用指向它时,那么这个对象的引用就+1;
- 当一个对象的引用为0时,这个对象就可以被销毁掉;
PS: 这个算法的弊端就是会产生循环引用 就是加入 a b之间互有属性引用 会出现两个对象哦都无法销毁的问题
常见的GC算法 – 标记清除(mark-Sweep)
这个算法的核心思想是实现可达性
设置一个根对象(root object),垃圾回收器会定期从这个根开始,找所有从根开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象
PS:这个算法可以很好的解决循环引用的问题
- 他会从一个根对象去不断查找确认查找之后就会标记对象
- 如果发现找不到 就等于无法引用 那么就会去销毁(如下图)
- 前提是 RO 对象不会被删除 其实就代表我们 js 中的 window对象
拓展
其他的GC算法
- 标记整理算法(Mark-Compact) 回收的时候保留存储对象搬运到灰级连续的内存空间,整合空闲空间,避免内存碎片化
- 分代收集(Generational collection) 对象分为旧 新 两组 有很多对象在完成工作后就会销毁 长期存活的对象变为
老旧
同时他们的检查频次不会那么频繁 - 增量收集(Incremental collection)
- 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟
- 所以引擎试图将垃圾收集工作分成几部分来做,然后将这几部分会逐一进行处理,这样会有许多微小的延迟而不是一个大的延迟
- **闲时收集(Idle-time collection)**垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。
闭包概念
闭包是JavaScript中一个非常容易让人迷惑的知识点
JS 作为高级语言 是支持函数式编程的,这意味着在js中
- 函数操作和使用都非常灵活
- 函数可以作为另外一个函数的参数,也可以作为另外一个函数的返回值来使用
所以JavaScript存在很多的高阶函数,我们可以自己编写高阶函数,也可以使用内置的函数
在未来开源框架中也都是趋向于函数式编程
闭包的定义
- 最早出现的闭包是 Scheme
- 闭包实际上是一种存储了函数和关联环境的结构体
- 他和函数最大的区别就是闭包被捕捉的时候,他的自由变量会被锁定 即使脱离了捕捉时的上下文也可以照常运行
他的作用就是让我们可以在函数中访问到外围的变量,替我们省去了很多繁杂的变量处理
闭包小案例
function createAdder(count){
funtion adder(num){
return count+num
}
return adder
}
var adder5 = createAdder(5)
adder(100) // 100+5
这个例子可以很容易的看出闭包的使用和带来的好处
PS: 使用闭包的时候最好是可以将不需要的函数或者属性置为 null 来帮助GC回收释放对象 ,否则内存泄露会加大内存的占用
浏览器对于闭包的优化: 使用闭包的时候 浏览器会将我们没有使用的多余属性释放来增加性能