GC 算法
1. 援用计数
核心思想:设置援用数,判断以后援用是否为0
长处:
- 发现垃圾时,立刻回收
- 最大限度缩小程序暂停
毛病:
- 无奈回收循环援用的对象
- 工夫开销大(须要监听计数值的变动)
function fn() { const obj1 = {} const obj2 = {}}
2. 标记革除
核心思想:分标记和革除两个阶段
毛病:
1、 空间碎片化(回收对象在地址上的不间断)
2、 不能立刻回收
3. 标记整顿
标记,而后将流动对象的地址进行整顿,尽量使得流动对象地址间断
4. 分代回收
回收新生代对象(存活工夫较短的变量对象)
- 回收过程采纳复制算法+标记整顿
- 新生代内存辨别为两个等大小的空间
- 应用空间为From,用于存储流动对象, 闲暇空间为To,用于存储From中的流动对象
- 流动对象存储于From空间
- 标记整顿后将流动对象拷贝至To
- From 与To替换空间实现开释
回收细节:From和To之间的拷贝过程可能呈现降职(将新生代对象挪动至老生代)上面两种状况会产生降职
- 一轮GC后还存活的新生代须要降职
- To空间的使用率超过了25%
回收老生代对象
空间大,无奈应用复制算法,应用增量标记法优化效率
- 标记革除
- 标记整顿: 使得流动对象的地址间断
- 标记增量: 将本来标记整顿的工作拆分为多个小的标记工作,避免程序阻塞
V8
v8垃圾回收策略
v8内存有下限
- 采纳分代回收思维
- 内存分为新生代,老生代
- 针对不同对象,采纳不同算法
罕用算法
- 分代回收
- 空间复制
- 标记革除
- 标记整顿
- 标记增量
频繁GC(垃圾回收)会带来什么
- GC工作时,应用程序是进行的
- 频繁且过长的GC会导致利用假死
- 用户应用中感知利用卡顿
如何确定是否频繁回收垃圾:
- Timeline中频繁的回升降落
- 工作管理器中数据频繁的减少减小
堆快照查找拆散dom,这个都是无用的dom援用,须要应用堆快照性能超找
detachedNode
v8引擎执行流程
代码优化 函数嵌套会导致v8进行屡次的预解析,因而不要嵌套太深
堆栈操作
- js执行环境
- 执行环境栈(ECStack, execution context stack)
- 执行上下文
- VO(G),全局变量对象
- EC(G),全局执行上下文
根本类型 (栈操作)
- 根本数据类型是按值进行操作
- 根本数据类型值是寄存在栈区的
- 无论咱们以后看到的栈内存,还是后续援用数据类型会应用的堆内存都属于计算机内存
- GO(全局对象)
援用类型 (堆操作)
函数执行
- 确定作用域链(以后执行上下文,下级执行上下文)
- 确定this指向,如果是在全局作用域那么就是window
- 初始化arguments对象
- 形参赋值
- 变量晋升(var申明的关键字,或者函数外部的function申明)
- 执行代码
- 如果函数外部没有被其余中央所援用,那么就会进行出栈操作,开释栈内存
闭包了解
function fn() { var a = 1 return function(b) { console.log(a + b) }}const f = fn()f(5)f10()
- 闭包是一种机制,通过公有的上下文来爱护其中的变量的一种机制
- 也能够认为,在创立的某一个执行上下文不被开释的时候 就造成了闭包
- 爱护、保留数据
循环增加事件,看闭包应用的取舍
如果应用闭包,进行多个事件的注册,因为闭包的起因,会申请一个对地址来保留,如果事件越多,那么申请的内存越多,因而须要用到事件代理
变量的申明
变量申明最好是放在局部变量,否则代码在执行的时候 查找作用域链上的变量会比拟花工夫, 比照上面两段代码 应用的是 jsbench这个工具
var i, str = ""function parseDom() { for(i = 0; i < 100; i++) { str += i }}parseDom()
function parseDom() { let str = '' for(let i = 0; i < 100; i++) { str += i }}parseDom()
变量缓存
- 数组长度
- 屡次应用的dom变量等
缩小判断层级
- 尽可能的缩小判断的层级,如果有嵌套判断,看看是否能够将判断条件往外提