什么是JS的垃圾回收机制?

JavaScript垃圾回收通过“可达性”判断对象是否为垃圾,以标记-清除为主流算法,从根对象出发标记可达对象,清除未标记的不可达对象;现代引擎如V8采用分代回收、增量回收等优化策略减少性能影响;内存泄漏常因未清理定时器、事件监听器、意外全局变量或闭包导致,需通过及时解除引用、避免强引用滞留等方式预防;合理使用性能工具分析内存使用,配合垃圾回收机制可有效提升程序性能。

什么是js的垃圾回收机制?

JavaScript的垃圾回收机制,说白了,就是一套自动管理内存的系统。它负责找出那些程序不再需要的内存空间,然后把它们清理掉,好让新的数据能有地方住。这对于我们开发者来说,简直是福音,省去了手动分配和释放内存的繁琐和易错。

解决方案

当我们在JavaScript中创建对象、变量、函数时,它们都会占用内存。但这些东西并非永生不灭,总有它们完成使命,不再被任何地方引用的那一刻。这时,如果任由它们占据着内存,系统就会越来越慢,直到崩溃。垃圾回收机制就是来解决这个问题的。

它的核心思想是“可达性”(Reachability)。一个对象,只要能从根(Root)对象(比如全局对象

window

global

,当前执行栈中的局部变量,以及活动函数的参数等)通过引用链条访问到,它就是“可达的”,也就是“活着的”。反之,如果一个对象从任何根都无法访问到,那它就是“不可达的”,也就是“垃圾”,可以被回收了。

目前最主流的垃圾回收算法是“标记-清除”(Mark-and-Sweep)。我总觉得这个过程,就像是系统在玩一场大型的“寻宝游戏”:

标记阶段(Mark Phase)垃圾回收器会从一系列“根”对象(比如全局对象、当前执行上下文中的变量等)开始,遍历所有能从这些根访问到的对象,给它们打上一个“活着的”标记。这个过程会沿着对象的引用链条一层层地往下找,凡是能被找到的,都算“活着的”。那些没有被标记到的,自然就是“死的”——也就是垃圾。清除阶段(Sweep Phase):在标记阶段结束后,垃圾回收器会遍历堆内存,把所有没有被标记的对象,也就是那些“死掉的”对象,从内存中清除掉,释放它们占据的空间。

当然,早期的浏览器也用过“引用计数”(Reference Counting),但那玩意儿有个致命的弱点:循环引用。两个对象互相指着对方,谁也走不掉,结果就是内存泄漏。这就像两个人互相锁着对方的门,谁也出不去,最后都饿死在屋里。所以,标记-清除就成了主流。现代的V8引擎(Chrome和Node.js都在用)在此基础上做了很多优化,比如“分代回收”(Generational Collection)和“增量回收”(Incremental Collection),以减少垃圾回收对程序性能的影响,让用户几乎感受不到它的存在。

JavaScript垃圾回收是如何判断哪些对象是“垃圾”的?

判断一个对象是否是“垃圾”,关键在于它是否“可达”。这可不是简单地看它有没有被引用,而是要看它是否能从一组特定的“根”对象那里,通过一系列的引用链条被访问到。

想象一下,内存空间就像一个巨大的网络,每个对象都是网络中的一个节点。而“根”对象,就是这个网络的入口。这些根通常包括:

全局对象(Global Object):在浏览器环境中是

window

,在Node.js中是

global

。任何直接挂载在它们下面的变量和函数,都是可达的。执行栈(Execution Stack):当前正在执行的函数中声明的局部变量、函数参数等。当前执行上下文中的其他活动对象:比如闭包捕获的外部变量等。

垃圾回收器会从这些根出发,沿着所有的引用关系,像“病毒传播”一样,把所有能“感染”到的对象都标记为“活着的”。那些无论如何都无法被“感染”到的对象,就意味着它们已经彻底失去了与程序运行的联系,无法再被访问和使用了。这些就是真正的“垃圾”,可以被无情地清理掉。所以,一个对象即使还有引用指向它,但如果这个引用链条的源头已经不可达了,那么这个对象最终还是会被回收的。

内存泄漏与JavaScript垃圾回收机制有何关联,我们该如何避免?

内存泄漏,简单来说,就是那些本应被垃圾回收机制清理掉的内存,因为某种原因没有被清理,导致内存占用持续增长,最终影响程序性能甚至崩溃。垃圾回收机制的初衷就是防止内存泄漏,但它并非万能,很多时候,内存泄漏是由于我们代码编写不当,制造了“假性可达”而引起的。

我个人在开发中,最常遇到的内存泄漏场景包括:

未清除的定时器(Timers)或事件监听器(Event Listeners)

如果你设置了一个

setInterval

setTimeout

,但没有在合适的时机调用

clearInterval

clearTimeout

,那么即使定时器内部引用的对象在逻辑上已经“用不着”了,但只要定时器还在运行,那些被引用的对象就仍然是可达的。同样,给DOM元素添加了事件监听器,但在元素被移除或组件销毁时没有调用

removeEventListener

,那么即使DOM元素从页面上消失了,事件监听器及其闭包捕获的变量仍然会存在,导致内存泄漏。避免方法:务必在组件卸载、页面切换等生命周期结束时,清理掉所有定时器和事件监听器。

意外的全局变量

在函数内部不使用

var

let

const

声明变量,直接赋值,例如

foo = "bar"

,这会在全局对象上创建一个属性。全局变量在页面关闭前都不会被回收。避免方法:始终使用

var

let

const

声明变量,避免污染全局作用域。开启严格模式

'use strict'

也能有效防止这类问题。

闭包(Closures)的不当使用

闭包本身是JavaScript非常强大的特性,但如果一个闭包捕获了外部作用域中一个非常大的对象,并且这个闭包本身又被长期持有(比如作为某个全局对象的属性,或者作为未清除的事件回调),那么被捕获的大对象就无法被回收。避免方法:审慎使用闭包,尤其是在处理大量数据时。如果闭包只为了访问外部作用域中的一小部分数据,可以考虑将这部分数据作为参数传入,或者在不需要时显式地解除引用。

脱离DOM的引用

当你从DOM树中移除了一个元素,但你的JavaScript代码中仍然持有对这个元素的引用(比如在一个数组或对象中),那么这个元素及其子元素,以及它们关联的数据,都无法被垃圾回收。避免方法:在移除DOM元素后,及时将JavaScript中对应的引用设置为

null

,解除对它们的强引用。

解决内存泄漏的关键在于理解“可达性”的本质,并养成良好的编程习惯,主动在不再需要时解除引用,而不是盲目依赖垃圾回收器。

JavaScript垃圾回收会影响程序性能吗?我们能优化吗?

答案是肯定的,JavaScript的垃圾回收机制确实会影响程序性能。虽然它在后台默默工作,替我们省去了大量麻烦,但这个“打扫卫生”的过程,有时会占用CPU时间,甚至可能导致程序出现短暂的卡顿,也就是所谓的“暂停”(Pause)或“停顿”(Stop-the-world)。

这是因为在传统的标记-清除过程中,为了确保内存状态的一致性,垃圾回收器在执行时需要暂停JavaScript应用程序的执行。如果堆内存很大,需要回收的垃圾很多,那么这个暂停时间就会变长,用户就会感觉到明显的卡顿。

不过,现代的JavaScript引擎(如V8)已经对垃圾回收进行了大量优化,以最大程度地减少这种影响:

分代回收(Generational Collection):V8将堆内存分为“新生代”(New Space)和“老生代”(Old Space)。新生代:用于存放生命周期较短的对象。新生代中的对象会频繁地进行小范围的回收,速度很快,因为大部分对象很快就会“死亡”。老生代:用于存放生命周期较长的对象(经过多次新生代回收后仍然存活的对象)。老生代的回收频率较低,但由于对象数量和大小都更大,回收时间相对较长。这种策略基于“弱代假说”:大部分对象生命周期很短,少数对象生命周期很长。增量回收(Incremental Collection):将垃圾回收任务分解成多个小块,分批执行。在每个小块执行之间,JavaScript应用程序可以继续运行,从而减少了单次暂停的时间,使得用户体验更流畅。并发回收(Concurrent Collection)并行回收(Parallel Collection)并发回收:垃圾回收器的一部分工作可以与JavaScript应用程序同时进行,不阻塞主线程。并行回收:垃圾回收器利用多核CPU的优势,同时使用多个线程来执行回收任务,从而缩短回收时间。

我们能做的优化

尽管引擎已经很智能,但我们作为开发者,仍然可以通过一些策略来帮助垃圾回收器,间接优化程序性能:

减少不必要的对象创建:尤其是在循环或频繁调用的函数中,避免创建大量临时对象。尽可能重用对象,或者使用对象池(虽然这在JS中通常是过度优化)。及时解除引用:当一个对象不再需要时,显式地将其引用设置为

null

。这会帮助垃圾回收器更快地识别出它为垃圾。避免内存泄漏:这是最重要的。如前所述,清理定时器、事件监听器,避免全局变量和不当的闭包使用,是减少垃圾回收压力的关键。注意大型数据结构:如果你的应用程序需要处理大量数据,考虑如何高效地存储和访问它们,避免一次性加载所有数据到内存。使用性能分析工具:Chrome DevTools里的Memory面板,简直是排查这类问题的利器。它能帮助你监控内存使用情况,发现内存泄漏点,甚至记录堆快照,分析哪些对象占据了大部分内存,哪些对象迟迟不被回收。没有它,我们很多时候就像在黑暗中摸索。

总而言之,我们不应该去“对抗”垃圾回收,而是要“配合”它。通过编写更内存友好的代码,我们可以让垃圾回收器的工作更轻松、更高效,从而提升整个应用程序的性能和响应速度。

以上就是什么是JS的垃圾回收机制?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1518404.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 11:32:10
下一篇 2025年12月20日 11:32:23

相关推荐

  • 您不需要 CSS 预处理器

    原生 css 在最近几个月/几年里取得了长足的进步。在这篇文章中,我将回顾人们使用 sass、less 和 stylus 等 css 预处理器的主要原因,并向您展示如何使用原生 css 完成这些相同的事情。 分隔文件 分离文件是人们使用预处理器的主要原因之一。尽管您已经能够将另一个文件导入到 css…

    2025年12月24日
    000
  • React 嵌套组件中,CSS 样式会互相影响吗?

    react 嵌套组件 css 穿透影响 在 react 中,嵌套组件的 css 样式是否会相互影响,取决于采用的 css 解决方案。 传统 css 如果使用传统的 css,在嵌套组件中定义的样式可能会穿透影响到父组件。例如,在给出的代码中: 立即学习“前端免费学习笔记(深入)”; component…

    2025年12月24日
    000
  • React 嵌套组件中父组件 CSS 修饰会影响子组件样式吗?

    对嵌套组件的 CSS 修饰是否影响子组件样式 提问: 在 React 中,如果对嵌套组件 ComponentA 配置 CSS 修饰,是否会影响到其子组件 ComponentB 的样式?ComponentA 是由 HTML 元素(如 div)组成的。 回答: 立即学习“前端免费学习笔记(深入)”; 在…

    2025年12月24日
    000
  • 在 React 项目中实现 CSS 模块

    react 中的 css 模块是一种通过自动生成唯一的类名来确定 css 范围的方法。这可以防止大型应用程序中的类名冲突并允许模块化样式。以下是在 react 项目中使用 css 模块的方法: 1. 设置 默认情况下,react 支持 css 模块。你只需要用扩展名 .module.css 命名你的…

    2025年12月24日
    000
  • action在css中的用法

    CSS 中 action 关键字用于定义鼠标悬停或激活元素时的行为,语法:element:action { style-property: value; }。它可以应用于 :hover 和 :active 伪类,用于创建交互效果,如更改元素外观、显示隐藏元素或启动动画。 action 在 CSS 中…

    2025年12月24日
    000
  • css规则的类型有哪些

    CSS 规则包括:通用规则:选择所有元素类型选择器:根据元素类型选择元素类选择器:根据元素的 class 属性选择元素ID 选择器:根据元素的 id 属性选择元素(唯一)后代选择器:选择特定父元素内的元素子选择器:选择作为特定父元素的直接子元素的元素伪类:基于元素的状态或特性选择元素伪元素:创建元素…

    2025年12月24日
    000
  • 深入理解CSS框架与JS之间的关系

    深入理解CSS框架与JS之间的关系 在现代web开发中,CSS框架和JavaScript (JS) 是两个常用的工具。CSS框架通过提供一系列样式和布局选项,可以帮助我们快速构建美观的网页。而JS则提供了一套功能强大的脚本语言,可以为网页添加交互和动态效果。本文将深入探讨CSS框架和JS之间的关系,…

    2025年12月24日
    000
  • 项目实践:如何结合CSS和JavaScript打造优秀网页的经验总结

    项目实践:如何结合CSS和JavaScript打造优秀网页的经验总结 随着互联网的快速发展,网页设计已经成为了各行各业都离不开的一项技能。优秀的网页设计可以给用户留下深刻的印象,提升用户体验,增加用户的黏性和转化率。而要做出优秀的网页设计,除了对美学的理解和创意的运用外,还需要掌握一些基本的技能,如…

    2025年12月24日
    200
  • 学完HTML和CSS之后我应该做什么?

    网页开发是一段漫长的旅程,但是掌握了HTML和CSS技能意味着你已经赢得了一半的战斗。这两种语言对于学习网页开发技能来说非常重要和基础。现在不可或缺的是下一个问题,学完HTML和CSS之后我该做什么呢? 对这些问题的答案可以分为2-3个部分,你可以继续练习你的HTML和CSS编码,然后了解在学习完H…

    2025年12月24日
    000
  • 聊聊怎么利用CSS实现波浪进度条效果

    本篇文章给大家分享css 高阶技巧,介绍一下如何使用css实现波浪进度条效果,希望对大家有所帮助! 本文是 CSS Houdini 之 CSS Painting API 系列第三篇。 现代 CSS 之高阶图片渐隐消失术现代 CSS 高阶技巧,像 Canvas 一样自由绘图构建样式! 在上两篇中,我们…

    2025年12月24日 好文分享
    200
  • 巧用距离、角度及光影制作炫酷的 3D 文字特效

    如何利用 css 实现3d立体的数字?下面本篇文章就带大家巧用视觉障眼法,构建不一样的 3d 文字特效,希望对大家有所帮助! 最近群里有这样一个有意思的问题,大家在讨论,使用 CSS 3D 能否实现如下所示的效果: 这里的核心难点在于,如何利用 CSS 实现一个立体的数字?CSS 能做到吗? 不是特…

    2025年12月24日 好文分享
    000
  • CSS高阶技巧:实现图片渐隐消的多种方法

    将专注于实现复杂布局,兼容设备差异,制作酷炫动画,制作复杂交互,提升可访问性及构建奇思妙想效果等方面的内容。 在兼顾基础概述的同时,注重对技巧的挖掘,结合实际进行运用,欢迎大家关注。 正文从这里开始。 在过往,我们想要实现一个图片的渐隐消失。最常见的莫过于整体透明度的变化,像是这样: 立即学习“前端…

    2025年12月24日 好文分享
    000
  • css实现登录按钮炫酷效果(附代码实例)

    今天在网上看到一个炫酷的登录按钮效果;初看时感觉好牛掰;但是一点一点的抛开以后发现,并没有那么难;我会将全部代码贴出来;如果有不对的地方,大家指点一哈。 分析 我们抛开before不谈的话;其实原理和就是通过背景大小以及配合位置达到颜色渐变的效果。 text-transform: uppercase…

    2025年12月24日
    000
  • CSS flex布局属性:align-items和align-content的区别

    在用flex布局时,发现有两个属性功能好像有点类似:align-items和align-content,乍看之下,它们都是用于定义flex容器中元素在交叉轴(主轴为flex-deriction定义的方向,默认为row,那么交叉轴跟主轴垂直即为column,反之它们互调,flex基本的概念如下图所示)…

    2025年12月24日 好文分享
    000
  • 手把手教你用 transition 实现短视频 APP的点赞动画

    怎么使用纯 css 实现有趣的点赞动画?下面本篇文章就带大家了解一下巧妙借助 transition实现点赞动画的方法,希望对大家有所帮助! 在各种短视频界面上,我们经常会看到类似这样的点赞动画: 非常的有意思,有意思的交互会让用户更愿意进行互动。 那么,这么有趣的点赞动画,有没有可能使用纯 CSS …

    2025年12月24日 好文分享
    000
  • 巧用CSS实现各种奇形怪状按钮(附代码)

    本篇文章带大家看看怎么使用 CSS 轻松实现高频出现的各类奇形怪状按钮,希望对大家有所帮助! 怎么样使用 CSS 实现一个内切角按钮呢、怎么样实现一个带箭头的按钮呢? 本文基于一些高频出现在设计稿中的,使用 css 实现稍微有点难度和技巧性的按钮,讲解使用 css 如何尽可能的实现它们。【推荐学习:…

    2025年12月24日 好文分享
    000
  • 原来利用纯CSS也能实现文字轮播与图片轮播!

    怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯css也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助! 今天,分享一个实际业务中能够用得上的动画技巧。【推荐学习:css视频教程】 巧用逐帧动画,配合补间动画实现一个无限循环的轮播效果,像是这样: 立即学习“前端…

    2025年12月24日 好文分享
    000
  • HTML+CSS+JS实现雪花飘扬(代码分享)

    使用html+css+js如何实现下雪特效?下面本篇文章给大家分享一个html+css+js实现雪花飘扬的示例,希望对大家有所帮助。 很多南方的小伙伴可能没怎么见过或者从来没见过下雪,今天我给大家带来一个小Demo,模拟了下雪场景,首先让我们看一下运行效果 可以点击看看在线运行:http://hai…

    2025年12月24日 好文分享
    500
  • 总结整理:需要避坑的五大常见css错误(收藏)

    本篇文章给大家总结5个最常见的css错误,并介绍一下避坑方法,希望对大家有所帮助! 正如我们今天所知,CSS语言是web的一个重要组成部分。它使我们有能力绘制元素在屏幕、网页或其他媒体中的展示方式。 它简单、强大,而且是声明式的。我们可以很容易地实现复杂的事情,如暗黑/光明模式。然而,对它有很多误解…

    2025年12月24日
    000
  • CSS+JS实现爱心点赞按钮(代码示例)

    本篇文章给大家介绍一下css+js实现一个“爱之满满”点赞按钮的方法,希望对大家有所帮助! 前段时间在看一档说唱节目,被里面的一个说唱歌手JBcob的爱之满满这句词给洗脑了。 于是这次给大家带来一个爱之满满的点赞按钮,让大家在点赞的同时还能感受到被爱包裹的感觉。 立即学习“前端免费学习笔记(深入)”…

    2025年12月24日 好文分享
    000

发表回复

登录后才能评论
关注微信