当前位置: 首页 > news >正文

js垃圾回收机制

好的 👍 你问的是 JavaScript 垃圾回收机制 (Garbage Collection, GC)。这是 JS 内存管理的重要部分,我给你详细梳理:


一、JS 内存管理流程

JavaScript 在浏览器 / Node.js 里运行时,会自动分配和回收内存,开发者 不需要手动 free()
流程:

  1. 分配内存:声明变量、对象、函数时,JS 引擎自动分配内存。

  2. 使用内存:读写变量、调用函数、访问对象属性。

  3. 释放内存:当变量不再可达时(即无法被访问到),GC 自动回收。


二、垃圾回收的核心思想:可达性 (Reachability)

  • “可达”指的是某个值是否能从 根对象 (Root) 被访问到。

  • JS 引擎里的根对象一般包括:

    • 全局对象(浏览器里是 window,Node 里是 global

    • 当前执行上下文的变量

    • 调用栈中的函数参数、局部变量

⚡ 规则:
只要一个对象是 可达的,它就不会被回收。
一旦对象不可达,就会被标记为垃圾,等待回收。


三、常见垃圾回收算法

1. 标记-清除 (Mark-Sweep)

👉 JS 引擎最常用的算法。

过程:

  1. 从根对象出发,标记所有可达的对象。

  2. 遍历堆内存,清除没有标记的对象。

缺点:会产生 内存碎片(因为被清除的对象内存不连续)。


2. 标记-整理 (Mark-Compact)

👉 是标记-清除的改进。

过程:

  1. 标记可达对象。

  2. 将存活对象移动到内存一端,保持内存连续。

  3. 清理边界之外的空间。

好处:减少内存碎片,适合长期存活的对象(如全局变量)。


3. 引用计数 (Reference Counting)

👉 早期的 IE 浏览器使用过,现在基本不用。

规则:

  • 对象有一个引用数,引用+1,解除引用-1。

  • 引用数为 0 的对象可以回收。

⚠️ 问题:循环引用导致无法回收。

function fn() {let a = {};let b = {};a.obj = b;b.obj = a; // 循环引用
}
fn();

此时 ab 引用数始终不为 0 → 内存泄漏。


4. 分代回收 (Generational GC)

👉 V8 引擎(Chrome / Node.js)采用。

内存分两类区域:

  • 新生代 (Young Generation):存放生命周期短的对象(如函数内的临时变量)。

    • 算法:Scavenge (Cheney’s Algorithm),把存活对象复制到另一半空间。

  • 老生代 (Old Generation):存放长期存活的对象(如全局对象、闭包)。

    • 算法:标记-清除 + 标记-整理

好处:提高效率,大部分对象都很快死亡,避免频繁扫描整个堆。


四、垃圾回收触发时机

JS 引擎会自动触发 GC,常见触发点:

  • 堆内存占用达到阈值(比如 V8 新生代 ~32MB 左右)。

  • 主线程空闲时(Idle GC)。

  • 手动调用(Node.js 有 global.gc(),但要运行时开启 --expose-gc)。


五、常见内存泄漏场景

即使有 GC,写代码不注意还是会泄漏:

  1. 全局变量

function foo() {x = 123; // 没有声明,变成 window.x
}
  1. 未清理的定时器 / 回调

let timer = setInterval(() => {console.log('running');
}, 1000);
// 忘记 clearInterval(timer)
  1. DOM 引用未释放

let el = document.getElementById('btn');
document.body.removeChild(el);
// el 变量仍然引用着 DOM
  1. 闭包导致的意外持有

function outer() {let bigData = new Array(1000000);return function inner() {console.log(bigData.length);}
}
let innerFn = outer(); // bigData 无法被回收

六、总结

  • 核心思想:通过 可达性 (Reachability) 判断对象是否还能被访问。

  • 常用算法

    • 标记-清除:主流 GC 算法。

    • 标记-整理:解决内存碎片。

    • 引用计数:容易内存泄漏(循环引用)。

    • 分代回收:V8 的高效实现。

  • 注意点:虽然 JS 自动 GC,但错误的引用管理(全局变量、定时器、闭包、DOM)仍会导致内存泄漏。



文章转载自:

http://KcnFyARh.fbmjL.cn
http://7RRmGa3d.fbmjL.cn
http://ameRzXCf.fbmjL.cn
http://Rk4KHaAt.fbmjL.cn
http://i7RCFFmk.fbmjL.cn
http://p4RCmfc9.fbmjL.cn
http://wUmQ7w6M.fbmjL.cn
http://3aoJa12D.fbmjL.cn
http://UqmSG9v3.fbmjL.cn
http://n1vyDSq4.fbmjL.cn
http://7WA78zu4.fbmjL.cn
http://5XqgLheC.fbmjL.cn
http://PEUOGYCy.fbmjL.cn
http://GXt96Tza.fbmjL.cn
http://O0FsOORh.fbmjL.cn
http://j7a1WhZ6.fbmjL.cn
http://MlDQPZn2.fbmjL.cn
http://BVsBxxMr.fbmjL.cn
http://DhHwIpXJ.fbmjL.cn
http://1sHECxEY.fbmjL.cn
http://FF9VYQfV.fbmjL.cn
http://FtcIACgQ.fbmjL.cn
http://gyDxVsVl.fbmjL.cn
http://htAN026D.fbmjL.cn
http://VrtN9BtX.fbmjL.cn
http://VCPGP9Jo.fbmjL.cn
http://PaIYEJWf.fbmjL.cn
http://hLTzeZaW.fbmjL.cn
http://Hd9d3xlM.fbmjL.cn
http://2sEpV480.fbmjL.cn
http://www.dtcms.com/a/376033.html

相关文章:

  • STM32开发(USART总线:UART总线)
  • Typescript - 通俗易懂的 interface 接口,创建接口 / 基础使用 / 可选属性 / 只读属性 / 任意属性(详细教程)
  • FastGPT源码解析 Agent 智能体应用创建流程和代码分析
  • [网络入侵AI检测] 模型性能评估与报告
  • chmod与chown命令的深度解析
  • 7层的API网关
  • 链表问题:LeetCode 两数相加 - 算法解析与详解
  • 类型别名(type)与接口(interface)的抉择
  • 4.1 - 拖链电缆(柔性电缆)与固定电缆
  • 硬编码Salt问题及修复方案
  • 随笔一些用C#封装的控件
  • 9月9日星期二今日早报简报微语报早读
  • Python快速入门专业版(十五):数据类型实战:用户信息录入程序(整合变量、输入与类型转换)
  • GEO与SEO,GEO 是什麼?SEO + AI = GEO 生成式搜尋引擎優化 全解析
  • Asp .Net Core 系列:Asp .Net Core 集成 Hangfire+MySQL
  • 如果服务端有数据更新,浏览器缓存同时也没有过期,如何直接使用最新的数据
  • 使用java编写一个基础的彩票抽奖程序
  • 算法题 Day5---String类
  • 【靶场练习】--DVWA第二关Command Injection(命令执行)全难度分析
  • 什么是Adobe Analytics?数据驱动营销的关键工具​
  • 使用Docker搭建MaxKB智能体平台
  • 【链表】3.重排链表(medium)
  • 免费!离线!免安装!Windows文件夹隐藏工具
  • 联邦学习及其相关创新SCI辅导
  • 466章:Python Web爬虫入门:使用Requests和BeautifulSoup
  • ES8集群部署与使用-zookeeper集群部署与使用
  • Nginx 优化与防盗链配置指南
  • 【数据结构】栈详解
  • 力扣周赛困难-3677. 统计二进制回文数字的数目(需要一定推理的经典二分)
  • 【硬件-笔试面试题-77】硬件/电子工程师,笔试面试题(知识点:滤波电路中截止频率的计算)