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

JavaScript 垃圾回收机制详解

JavaScript 垃圾回收机制详解

在 JavaScript 中,内存管理是自动的。当变量不再被需要时,它们所占用的内存会被垃圾回收器(Garbage Collector, GC)自动释放。理解 GC 原理有助于写出更高效、更不易内存泄漏的代码。


一、核心概念:可达性(Reachability)

垃圾回收的基本判断标准是可达性:从根(Root)对象出发,通过引用链可以访问到的对象,就是“可达的”,需要保留;无法到达的对象则被标记为垃圾,等待回收。

根对象通常包括

  • 全局对象(浏览器中为window,Node.js 中为global
  • 当前执行函数的局部变量和参数
  • 调用栈上的其他函数变量
  • 某些内置对象(如 DOM 树的根节点)
letuser={name:'Alice',friend:{name:'Bob'}};// user 引用对象 {name:'Alice', friend: ...} 从根可达,对象存活user=null;// 现在 {name:'Alice', friend:{...}} 不再可达,GC 可回收

二、常见的垃圾回收算法

1. 引用计数(Reference Counting)

原理:每个对象维护一个引用计数器,记录有多少个地方引用了它。当引用计数降为 0 时,对象立即被回收。

leta={value:1};// 对象 {value:1} 引用计数 = 1letb=a;// 引用计数 = 2a=null;// 引用计数 = 1b=null;// 引用计数 = 0 → 立即回收

致命缺点:循环引用

functioncreateCycle(){letobj1={};letobj2={};obj1.ref=obj2;obj2.ref=obj1;return'done';}createCycle();// obj1 和 obj2 互相引用,即使函数执行完毕离开作用域,它们的引用计数仍为 1,永远无法回收。

优点:实现简单,回收及时,没有明显暂停。

缺点:无法处理循环引用;计数器维护带来额外开销(每次赋值都要更新)。现代 JS 引擎已不采用此方案作为主要算法,仅在某些场景(如 COM 对象)中保留。


2. 标记-清除(Mark-and-Sweep)

这是现代引擎的核心算法,完美解决循环引用问题。

流程

  1. 标记阶段:从根对象出发,深度遍历所有可达对象,并标记为“活跃”。
  2. 清除阶段:遍历整个堆内存,将未被标记的对象回收,并将内存归还给空闲列表。
// 循环引用示例functionfoo(){leta={};letb={};a.b=b;b.a=a;}foo();// 执行后,a, b 无法从根对象到达 → 标记阶段不会标记它们 → 被清除

优点:能处理循环引用。

缺点

  • 回收时会产生内存碎片(空闲内存不连续)。
  • 标记和清除可能导致全停顿(Stop-The-World),页面卡顿。

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

为了解决内存碎片问题而提出。它在标记阶段后增加整理阶段:将所有存活对象移动到内存一端,然后直接清理边界外的所有内存。

// 想象内存布局// 整理前:[A][ ][B][ ][C][ ] → 整理后:[A][B][C][ ]

优点:消除碎片,分配大对象更容易。

缺点:移动对象有额外开销,停顿时间更长。通常与分代回收配合使用。


4. 分代回收(Generational Collection)

几乎所有现代 JS 引擎(V8、SpiderMonkey)都采用分代假说

大多数对象“朝生暮死”,存活时间短;少数对象存活时间长。

引擎将内存堆划分为新生代(Young Generation)老生代(Old Generation),分别使用不同策略。

新生代(Young Generation)
  • 存放存活时间短的对象,空间较小(通常 1~8 MB)。
  • 回收算法:Scavenge(半空间复制)
  • 将新生代分为两个等大的半空间(From 和 To)。
    • 分配都在 From 空间进行。
    • 当 From 空间快满时触发 Minor GC:
      • 标记 From 空间的存活对象。
      • 将存活对象复制到 To 空间,并紧凑排列。
      • 交换 From 和 To 的角色。
  • 优点:速度快,只处理存活对象,复制同时完成了整理。
  • 对象晋升:经过两次 Minor GC 仍存活的对象,会移动到老生代。
老生代(Old Generation)
  • 存放存活时间长的对象,空间大(可达几百 MB)。
  • 回收算法:标记-清除+标记-整理(Major GC)。
  • 通常在老生代内存不足时触发,频率低,但停顿时间长。

三、V8 引擎的优化手段

为了减少全停顿带来的卡顿,V8 采用了多种技术将垃圾回收工作拆解到多个小步中执行。

技术说明
增量标记(Incremental Marking)将标记阶段拆成许多小段,与 JS 执行交替进行,每执行一小段 JS 就标记一点,缩短连续停顿时间。
惰性清理(Lazy Sweeping)按需清理垃圾页,不必一次性清扫整个堆,减少清理阶段的暂停。
并发标记(Concurrent Marking)标记工作完全在后台线程中执行,JS 主线程可以持续运行,几乎无停顿。
并发清理(Concurrent Sweeping)清理也在后台线程进行,主线程仅需短暂同步。
并行回收主线程和多个辅助线程同时进行回收工作,利用多核加速。

V8 的分代回收简图

堆内存 ├── 新生代 (Young Gen) │ ├── From 空间 (活动区) │ └── To 空间 (空闲区) ← Scavenge 算法 │ ↳ 两次存活 → 晋升到老生代 └── 老生代 (Old Gen) ├── 标记-清除 / 标记-整理 ├── 增量标记 / 并发标记 └── 惰性清理

四、开发者如何配合 GC

虽然 GC 是自动的,但不规范的代码会造成内存泄漏,导致性能下降甚至崩溃。

常见内存泄漏及避免方法
  1. 全局变量意外污染
functionleak(){bar='this is global';// 未声明变量,挂载到 window}
  1. 遗忘的定时器或回调
constobj={data:newArray(10000).fill('*'),start(){this.timer=setInterval(()=>{console.log(this.data);},1000);}};// 组件卸载时必须 clearInterval(this.timer),否则 obj 无法被回收
  1. 闭包引用大对象
functionouter(){constbigData=newArray(1000000);returnfunctioninner(){console.log('hello');// bigData 虽然未在 inner 中使用,但因闭包作用域链,可能被 V8 保留};}constfn=outer();// bigData 常驻内存// 优化:将 bigData = null 在 return 前释放
  1. 游离的 DOM 引用
letbtn=document.getElementById('myBtn');btn.remove();// 从 DOM 树移除,但 JS 变量 btn 仍引用它,GC 不回收btn=null;// 手动清除引用
现代辅助工具
  • WeakRef:创建对对象的弱引用,不阻止 GC。
  • FinalizationRegistry:在对象被回收后执行回调,用于清理资源。
letobj={data:'important'};constregistry=newFinalizationRegistry((heldValue)=>{console.log(`对象被回收,清理资源:${heldValue}`);});registry.register(obj,'some resource');obj=null;// 未来 GC 回收后触发回调

总结

  • JavaScript 垃圾回收基于可达性
  • 核心算法从引用计数演进到标记-清除,再配合分代回收增量/并发优化以降低停顿。
  • 开发者应养成良好的内存管理习惯,避免循环引用、清除定时器、及时解除 DOM 引用等,利用弱引用处理特定场景。

理解这些机制后,你不仅能写出更高效的代码,还能在排查内存问题时快速定位根因。

http://www.rkmt.cn/news/1423600.html

相关文章:

  • 【字节跳动】江苏苏州江南水乡临水低碳液冷算力集群
  • UE5 蓝图 FPS 02 Event Beginplay
  • 【案例教程】CASA(Carnegie-Ames-Stanford Approach)模型原理及实践应用
  • 如何免费解锁完整游戏修改体验:WandEnhancer终极指南
  • 从Excel到Lindy全自动入职:3天完成87%人力事务闭环,中小企速效转型手册
  • 论文降AIGC率神器实测,10款工具对比稳过高校检测
  • 【字节跳动】海南文昌滨海海风潮汐风冷超算枢纽
  • PCIe-7.3.3 Configuration Request Routing Rules
  • 数字孪生赋能建筑行业 解锁工程全周期智慧管理
  • 2026最新临沂郯城黄金回收+白银回收+铂金回收店铺门店权威榜单TOP1~5家推荐地址电话 - 五金回收
  • 从Fusion 360建模到手工制作:打造独一无二的齿轮时钟全流程指南
  • 搜索引擎优化 快速提升网站排名的秘诀
  • 洛雪音乐助手:一站式聚合音乐播放器,告别多平台切换烦恼
  • CRM 客户管理系统如何避免客户资源流失
  • 【字节跳动】陕西榆林大漠风光风电直驱风冷超算母港
  • 2026 年 5月截止阀源头厂家推荐榜单:电动/法兰/高温/不锈钢/气动/高压截止阀,铸钢锻钢止回阀与调压阀专业实力之选 - 企业推荐官【官方】
  • 海龟通道落地时最易踩坑:get_kline_serial 序列对齐与冷启动
  • 3分钟快速激活Windows和Office:KMS智能激活工具完整指南
  • 回溯路径不可逆?Claude动态约束回溯引擎首次曝光:支持实时语义回滚与多目标 Pareto 剪枝
  • 科技与光影的浪漫交织,华硕携手风光Pixel 365打造影像盛宴
  • DevEco Studio——api24虚拟机创建
  • 2026最新黄冈黄州黄金回收+白银回收+铂金回收店铺门店权威榜单TOP1~5家推荐地址电话 - 金诚回收
  • 不同嵌段比例 PS-b-PEO 的可控合成及结构与热性能表征
  • 国家级基金加持,创始人感悟:真正难的是让客户长期信任
  • 【Lindy售后服务自动化落地指南】:20年实战总结的7大避坑法则与3步速成路径
  • RAG 系统踩坑:管理后台删除文档后,客服系统崩了
  • 2026年5月激光切割机厂家推荐排行榜:光纤激光切割机,万瓦激光切割机,龙门激光切割机,大幅面激光切割机源头厂家精选 - 企业推荐官【官方】
  • 【字节跳动】重庆武陵山峡谷云雾天然风冷智算集群
  • 【桌面霸主】Anthropic Computer Use API 详解:真正接管操作系统的里程碑
  • Claude用户手册制作:为什么90%的团队还在用Word写?真正驱动 Adoption 的3层智能文档架构