垃圾回收机制
js是使用垃圾回收的语言,执行环境负责在代码执行时管理内存
js是通过自动内存管理实现内存分配和闲置资源的回收
思路:确定哪个变量不会再使用,然后释放它。
垃圾回收是周期性的。
标记清理
首先为所有变量加上标记,然后将处在上下文的标量的标记去掉,之后假如再被加上标记的变量则是需要回收的变量。
引用计数
内存管理
- 内存:由可读写单元组成,表示一片可操作空间;
- 管理:人为的去操作一片空间的申请、使用和释放;
- 内存管理:开发者主动申请空间、使用空间、释放空间;
- 管理流程:申请-使用-释放
全停顿
如果一个回收GC 需要50ms,则应用逻辑暂停50ms
js的垃圾回收
判断为垃圾的情况
对象不再被引用
对象不能从根上访问
GC
算法
常见的GC
算法如下:
- 引用计数
- 标记清除
- 标记整理
- 分代回收
引用计数
引用计数算法优点:
- 引用计数为零时,发现垃圾立即回收;
- 最大限度减少程序暂停;
引用计数算法缺点:
- 无法回收循环引用的对象;
- 空间开销比较大;
标记清除
核心思想:分标记和清除两个阶段完成。
- 遍历所有对象找标记活动对象;
- 遍历所有对象清除没有标记对象;
- 回收相应的空间。
标记清除算法最大的优点是能够回收循环引用的对象,它也是v8引擎使用最多的算法。
需要引入标记整理的算法
标记整理的缺点是:移动对象位置,不会立即回收对象,回收的效率比较慢。
增量标记
为了减少全停顿时间
性能优化
1.避免使用全局变量
- 全局变量会挂载在window下;
- 全局变量至少有一个引用计数;
- 全局变量存活更久,持续占用内存;
- 在明确数据作用域的情况下,尽量使用局部变量;
2.减少判断层级
3 减少数据读取次数,缓存
4 减少循环体活动
5 事件绑定优化
6 避开闭包陷阱
堆(heap)与栈(stack)
在JavaScript中简单数据类型是放在栈中的,复杂数据类型是放在堆中的。
基本类型:这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的
引用类型:引用类型,值大小不固定,栈内存中存放地址指向堆内存中的对象。是按引用访问的。
区别
栈(stack)会自动分配内存空间,会自动释放。堆(heap)动态分配的内存,大小不定也不会自动释放。
堆:队列优先,先进先出;由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。
栈:先进后出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
堆栈溢出
上边说道栈的数据会自动清除,而堆中的数据不会自动清除,需要手动清除。
每次存储数据,就会造成堆中的东西一直在增加,也就是当存储的数据达到某一限制时,就会造成堆栈溢出。
内存泄漏
当不断的向堆中存储数据,而不进行清理,这就是内存泄漏。(内存泄漏的结果就是堆栈溢出)
垃圾回收机制
js中只有自动清理。清理的对象也可以叫做 ‘孤儿对象’ 。(堆中的数据的地址在栈中没有任何引用,这个堆中的数据对象就叫孤儿对象)