1.理解
- JavaScript具有自动垃圾回收的机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中的内存使用,其原理就是:垃圾收集器会定期(周期性)找出哪些不在继续使用的变量,然后释放其内存。
- 但是这个过程不是实时的,因为其开销比较大,且GC时会停止响应其他操作,所以垃圾回收器会按照固定的时间间隔周期性的执行。
- 不再使用的变量也就是生命周期结束的变量
- 全局变量:生命周期直到浏览器卸载页面才会结束
- 局部变量:
- 在函数的执行过程中存在,而在这个过程中会为局部变量在栈/堆上分配对应的看空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束
- 而闭包中由于外部使用了函数内部的变量,所以该变量并不会结束,直到返回的函数也失去引用后,该变量的生命周期才会结束
- 闭包和垃圾回收机制
- 常用的垃圾回收机制
- 引用计数法
- 原理:跟踪记录每个值被引用的次数,当引用次数为0时,就会被释放
- 工作流程
- 声明了一个变量并赋值了一个引用类型数据,这个引用数据的引用次数就是1
- 若再把这个引用数据赋值给另一个变量,则引用次数变成2
- 当包含这个引用数据的变量又赋值了另一个值,则引用次数减1
- 当引用次数变成0时,说明无法访问这个变量了
- 当下次垃圾回收机制触发时,就会将其释放
- 缺点
- 当存在循环引用的时候,会导致变量无法清除
- 标记清除法
- 原理:当变量进入环境后,会将变量标记为
进入环境,当变量离开环境后,会被标记为离开环境,离开环境的就会被释放掉 - 工作流程
- 垃圾回收器运行时,会将存储在内存中的所有变量都打上标记
- 然后清除掉在环境中的变量一级被环境中变量引用的变量的标记
- 之后会清除掉被标记的变量
- 缺点
- 当变量被清除后,会导致内存变得不连续,也就是所谓的内存碎片,当然,引用计数法也存在这种问题,所以也就有了
标记整理清除法
- 当变量被清除后,会导致内存变得不连续,也就是所谓的内存碎片,当然,引用计数法也存在这种问题,所以也就有了
- 原理:当变量进入环境后,会将变量标记为
- 标记整理清除法
- 在标记清除法之上,又对内存重新进行了整理,即将不连续的内存整理成连续的内存
- 引用计数法
// 循环引用 引用计数法的缺点
function test() {
const a = new Object(); // a:1
const b = new Object(); // b:1
a.b = b; // b:1+1
b.a = a; // a:1+1
// a = null; // a:1+1-1
// b = null; // b:1+1-1
}
理解:
- 当执行test函数时,会创建a和b对象,此时各自标记为1
- 紧接着又分别给 a.b 和 b.a 赋值了a和b对象,此时 各自的标记又加1,为2
- 当函数执行完毕后,a变量和b变量会被赋值为null(null表示空引用,即回收)
- 所以 a对象和b对象的标记各自减1,即为2
- 因为a变量和b变量都销毁了,所以也不存在a.b和b.a
- 但此时的a对象和b对象的标记为1,导致GC无法清理
- 正确的清理方式应该为
- 在函数执行完毕之前,将 a.b = null; b.a = null; 进行标记清理
2.v8引擎中的内存管理
- V8 的垃圾回收策略主要基于
分代式垃圾回收机制,V8 中将堆内存分为新生代和老生代两区域,采用不同的垃圾回收器也就是不同的策略管理垃圾回收`- 新生代(1~8M)
- 新生代主要存放新进入环境的变量
- 新生代又分为
空闲区和使用区 - 当新的变量进入环境后,会被存放在使用区
- 当使用区快要被写满时,垃圾清理操作就需要执行,在垃圾回收之前,新生代回收器会对使用区中的活动对象进行标记,标记完成后,活动对象会被复制到空闲区进行排序(即不存在内存碎片)
- 垃圾清理阶段开始,即将非活动对象占用的空间清理掉
- 最后,进行角色互换,即将原来的使用区变成空闲区,空闲区变成使用区
- 其中,若一个对象经过多次复制后依然存活,那么它将会被认为是生命周期较长的对象,且会被移动到老生代中进行管理,此外,若复制一个对象到空闲区,空闲区的空间占用超过25%,那么这个对象也会移动到老生代中,25%的比例是为了避免影响后续内存分配
- 老生代
- 老生代存放的主要是使用相对频繁并且短时间内无需清理的内容,这部分内容可以采用标记整理清除法
- 新生代(1~8M)
3.并行回收
JavaScript 为单线程,所以在处理任务时,有可能会阻塞,并行回收则是在主线程的基础上,又开辟了子线程一块进行处理(即本来一个干的活,现在叫了三个人来干,缩短了时间)
4.全停顿标记
即进行GC操作时,会阻塞其他任务的执行
5.切片标记
将GC操作进行切片,分布在cpu的空闲时间进行执行