自动管理内存机制-JS 垃圾回收机制

163 阅读5分钟

JS引擎

JS都有哪些引擎

V8引擎是Chrome开发的高性能的JS引擎;采用JIT即时编码技术极大提高了代码的执行速度;内存管理方面使用了分代式垃圾回收机制来有效管理内存,这使得他在性能和效率上表现出色;

JS引擎运行的过程:

解析、编译、执行

JS引擎主要功能:

  • 语法解析:检查代码是否符合js语法规则, 不符合抛出错误
  • 作用域管理:创建和管理变量作用域,确定变量的访问范围和生命周期
  • 内存管理:垃圾自动回收机制, 回收不再使用的对象所占的内存空间
  • 对象管理:创建、操作和销毁对象

什么是垃圾回收

JS 有自动垃圾回收机制,垃圾回收器会跟踪对象,定期找出不被引用的对象或变量, 释放其所占的内存;最常用的有标记清除和引用计数两种算法

现代 JavaScript 引擎(如 V8引擎)通常会综合使用这些算法,根据不同的场景和对象特性选择最合适的垃圾回收策略,以达到性能和内存管理的平衡。

  • V8引擎的垃圾回收机制 是 js垃圾回收机制在V8这个特定环境下的实现;
    • js语言规范规定了内存自动管理的理念
    • v8将理念化为实际的算法和策略

1. 引用计数:

定义:

引用计数是用于内存管理的算法;通过跟踪对象的引用数量来决定是否回收内存。

核心思想:

当一个对象被引用时,他的引用计数+1;当引用移除时候;引用计数-1;当引用计数为0;则表示可以被回收了

缺点

  • 循环引用的问题:如果ab互相引用,那么计数永远不能为0,存在内存泄漏的问题
  • 性能开销:频繁的引用计数更新会带来一定的性能开销,特别是在对象引用频繁变化的情况下。

优点:

  • 算法简单
  • 实时性比标记清除, 因为标记清除需要等待垃圾回收器的周期执行;而对象的引用计数为0时,可立即回收内存

解决:

虽然引用计数算法简单,但由于其循环引用的问题,现代 JavaScript 引擎(如 V8)并不单纯使用引用计数算法,而是结合标记 - 清除等算法;标记 - 清除算法可以解决循环引用的问题,它通过标记可达对象,清除不可达对象,在一定周期内执行,与引用计数算法互补,共同实现更高效的垃圾回收。

2. 标记清除

工作原理:

  1. 遍历-标记-可达
  2. 遍历-未标记可达的 - 清除

从根对象开始,遍历所有可访问的对象,并将他们标记为可达,这个过程通常使用深度优先搜索或广度优先搜索;

遍历堆中所有对象,将未标记为可达的对象视为垃圾, 进行回收

优点:

可以解决循环引用问题:因为只要对象不可达(不被根对象引用),即使存在循环引用, 也会被标记为垃圾

缺点:

可能会产生内存碎片:因为回收的对象可能是不连续的,导致后续需要大内存的时候,无法分配;


其他垃圾回收机制:

  1. 标记整理解决内存碎片化,但移动对象会带来额外开销
  2. 标记复制:
  3. 分代收集:
    • 原理:新生代(标记复制) + 老生代(标记清除或者标记整理)
    • 优点:不同代对象采用不同的回收策略,提高回收效率
    • 缺点:需要更多内存空间来管理不同代的对象和复制操作
  4. 增量收集:
    • 工作原理:将垃圾回收任务分为多个小步骤,分阶段执行,避免长时间的垃圾回收暂停,提高响应能力,
    • 缺点:但实现复杂,需要更多的状态管理和上下文切换,可能会影响垃圾回收的总体性能;
    • 优点:减少垃圾回收导致的应用程序暂停
  5. 并发收集:
    • 工作原理:垃圾回收器和应用程序并发执行,在应用程序运行的同时进行部分垃圾回收工作。
    • 优点:最小化 垃圾回收对应用程序的影响
    • 缺点:实现复杂, 需要解决并发访问内存的同步问题

基于对象的生命周期将堆内存划分为不同的代,一般分为新生代和老生代。

常见的内存泄漏的方式:

  1. 闭包
  2. 意外的全局变量
  3. 事件监听没有移除

优化内存管理的方式:

在开发 JavaScript 应用时,虽然通常不需要直接操作垃圾回收机制,但了解这些算法可以帮助你更好地管理内存,避免内存泄漏和性能问题。例如,避免不必要的全局变量和闭包,及时释放不再使用的对象引用,以减轻垃圾回收的负担。

  1. 减少全局变量:如使用闭包封装或局部变量,因为全局变量存活时间长 不容易被垃圾回收
  2. 避免循环引用:可以使用WeakMap 弱引用
  3. 手动解除不再使用的对象引用:设置为null
  4. 局部作用域控制:减小作用域范围,可以更快释放

总结:

JS 有垃圾自动回收机制,常用的有引用计数 和标记清除两种算法,引用计数有循环引用的问题,所以 现代js引擎通常会结合其他算法来解决引用计数的不足,以实现可靠的垃圾回收机制; 除了引用计数,还有标记清除(有内存碎片的问题),标记整理(有移动开销的问题),标记复制,分代管理(实现复杂, 需要管理不同代对象和复制问题),增量收集(分段执行,较少暂停时间),并发收集(考虑并发问题)