js垃圾回收

JS垃圾回收

什么是垃圾回收?

自动将用不到的内存清理掉,避免浪费内存

什么是垃圾?

js 复制代码
let a = {name:"Tom"};
a = null;
//原来的{name:"Tom"}没人再用+没有变量指向它 -> 垃圾对象  

如何实现垃圾回收?

标记清除 (最核心)

如果一个对象是'不可达'的,那么它就是垃圾

第一阶段:标记(Mark)
  1. 垃圾回收器在运行时会给内存中所有的变量都打上一个初始标记(通常是 0)。
  2. 从"根对象"开始,递归地遍历所有引用。
  3. 凡是能被访问到的对象,都会被重新标记(比如改为 1),表示它们是"活跃的"或"可达的"。
  4. 遍历结束后,那些标记依然是 0 的对象,就是无法从根部触达的对象。
第二阶段:清除(Sweep)垃圾回收器对内存进行扫描。
  1. 销毁那些标记为 0 的对象,并回收它们所占用的空间。
  2. 最后,把所有存活对象的标记重新置为 0,等待下一轮回收。

引用计数

看一个对象被引用多少次,当引用次数为0就回收

但是!解决不了循环引用

js 复制代码
let a = {};
let b = {};
a.x = b;
b.x = a;
//互相引用,引用数不为0,但实际上没用 -> 内存泄漏

对比:原始类型的回收

原始类型不会像对象那样复杂回收:原始类型存在栈中,生命周期跟作用域绑定

js 复制代码
function fn() {
    let a = 10;
}

执行完:整个作用域直接销毁 -> a自动消失,不需要复杂GC,但是! 在js引擎内部仍然会统一由GC管理,只是回收成本极低,不需要可达性分析。

综上 :是否回收,不看类型,而是看有没有引用

分代垃圾回收

分代垃圾回收主要是针对堆中的对象设计的,把对象分为新生代和老生代,用不同策略回收,提高效率

新生代

特点:对象多,生命周期短。回收频繁

复制算法(From正在用 -> To空)

  1. 把活着的对象复制到To区
  2. 清空From区
  3. 交换空间(To区 → 新的From区)

对象经历多次GC还没死,就会进入老生代


老生代

对象少,生命周期长

标记清除、标记整理算法

  1. 标记阶段

    遍历所有存活对象,打上标记。

  2. 整理阶段

    存活对象往内存一端紧凑移动,更新引用地址,然后直接回收端外整片空间

好处 :无内存碎片

为什么频繁创建对象会卡顿?(GC卡顿)

原因:垃圾回收会暂停js执行(STW stop the world)

创建多 → 垃圾多 → GC 更频繁 → 卡顿更多

频繁创建对象会增加垃圾回收的频率,而垃圾回收过程中可能触发 Stop-The-World,暂停主线程执行,从而导致页面卡顿

现代引擎如何优化标记清除

虽然标记清除解决了循环引用问题,但它也有原生缺陷:

  1. 内存碎片化:清除对象后,空闲的内存空间是不连续的。如果此时需要分配一个大对象,可能会因为找不到足够大的连续空间而失败。
  2. 全停顿(Stop-the-World):在进行 GC 时,JavaScript 的执行必须暂停,这会导致页面卡顿(Jank)。

策略

  1. 标记整理

  2. 分代回收

  3. 增量标记:将原本漫长的"一次性标记"拆分成许多小步,每执行一小段 JS 代码,就执行一小步标记。这样将"大停顿"分散成许多"微停顿",让用户感觉不到卡顿。

  4. 三色标记法:配合增量标记使用,将对象分为:

    • 白色:未被访问,待回收
    • 灰色:已被访问,但其应用的子对象还未处理完
    • 黑色:已被访问且其引用的对象也以处理完,是安全的

    它是如何通过颜色实现"进度保存"的呢?

    1. 开始:所有对象都是白色。
    2. 标记根对象 :从根对象出发,把直接引用的对象涂成灰色,放入一个队列。
    3. 逐步扫描
      • 从队列取出一个灰色 对象,将其引用的子对象涂成灰色
      • 等这个对象所有的子对象都涂成灰色后,把当前对象涂成黑色
    4. 暂停与恢复
      • 暂停:因为有"灰色"这个中间状态,回收器知道哪些地方还没扫完。即使 JS 引擎暂停 GC 去执行业务代码,它只要记住"灰色对象队列"就行了。
      • 恢复:回来后,直接从灰色对象继续往下扫,不需要从头开始。

    结论:三色标记法让 GC 标记过程可以"走走停停",大大减少了单次停顿的时间。

相关推荐
小道士写程序2 小时前
3D雷达锥体 - Cesium兼容版
javascript
大黄说说2 小时前
Vue 3 + Vite 高性能项目最佳实践(2026 版)
前端·javascript·vue.js
予你@。2 小时前
# Vue2 + Element UI 表格合并实战:第二列按「第一列 + 第二列」条件合并
前端·javascript·vue.js
小J听不清2 小时前
CSS 文本对齐方式实战:text-align 核心用法
前端·javascript·css·html·css3
我爱学习_zwj2 小时前
设计模式-2(单例模式与原型模式)
前端·javascript·设计模式
霍理迪3 小时前
Vue—侦听属性
前端·javascript·vue.js
小J听不清3 小时前
CSS display 属性全解析:块级 / 行内 / 行内块 / 隐藏
前端·javascript·css·html·css3
早點睡3903 小时前
ReactNative项目Openharmony三方库集成实战:react-native-safe-area-context
javascript·react native·react.js
Jinuss3 小时前
React 19 新特性:`useOptimistic` Hook 完整指南
前端·javascript·react.js