浅谈垃圾回收、内存泄漏与闭包
什么是垃圾?
在js中,垃圾通常指的是不再被程序使用的内存或对象。也就是说,垃圾是指程序中分配的内存空间或对象,但不再被程序使用或无法被访问到的内容
function createIncrease() {const doms = new Array(100000).fill(0).map((item, i) => {const dom = document.createElement("div");dom.innerHTML = i;return dom;});function _increase() {doms.forEach((dom) => {dom.innerHTML = Number(dom.innerHTML + 1);});}return _increase;
}
const increase = createIncrease();
const btn = document.querySelector("#btn")
btn.addEventListener("click",increase)
上面的代码当执行createIncrease方法时,会创建一个increase方法,同时也会创建一个拥有100000个元素的doms数组,当btn点击时执行increase方法。此时的doms肯定不能称之为垃圾,因为当btn点击时需要使用doms,这种判断相对来说比较简单
const nums = [1, 2, 3, 4, 5];
const sum = nums.reduce((total, num) => total + num, 0);
上面的代码sum是由nums的每一项相加得出的结果,至于nums还会不会再次被使用,根本没法判断
因此,从上面对垃圾的阐述以及例子可以看出,是否为垃圾是由开发者自己决定的。通俗点说,当一段代码执行完成后不会再被使用,那么可以称之为垃圾
垃圾回收
垃圾回收是JavaScript中一种自动内存管理机制,用于检测和释放不再使用的对象,以便回收内存。垃圾回收器会定期扫描内存中的对象,并标记那些仍然被引用的对象,然后清除未被引用的对象垃圾回收器。换句话说,垃圾回收只回收
那些开发者自己都访问不了,无法触达的内存空间
垃圾回收算法:JavaScript 垃圾回收器使用不同的算法来确定内存中的对象是否可以被回收。常见的算法包括标记-清除、引用计数和增量标记等。标记-清除是最常用的算法,它通过标记不再需要的对象,然后清除它们来回收内存
function createIncrease() {const doms = new Array(100000).fill(0).map((item, i) => {const dom = document.createElement("div");dom.innerHTML = i;return dom;});function _increase() {doms.forEach((dom) => {dom.innerHTML = Number(dom.innerHTML + 1);});}return _increase;
}
const increase = createIncrease();
const btn = document.querySelector("#btn");
const flag = true;
function handleClick() {flag = false;if (flag) {increase();btn.removeEventListener("click", handleClick);increase = null;}
}
btn.addEventListener("click", handleClick);
const nums = [1, 2, 3, 4, 5];
const sum = nums.reduce((total, num) => total + num, 0);
nums = null
比如上面的代码:
- 当
btn被点击时执行increase方法,当点击完成后,移除btn点击事件以及将increase设置为null,此时就会被垃圾回收器回收 - 将
nums重新赋值为null时,那么之前声明的nums的内容我们就无法再访问,因此就会被回收
内存泄漏
内存泄漏是指当程序中的对象不再被使用,但由于某些原因仍然被保留在内存中,导致内存占用不断增加,最终耗尽可用内存的现象。
const timer = setTimeout(() => {// todo
}, 100);
const nums = [1, 2, 3, 4, 5];
const sum = nums.reduce((total, num) => total + num, 0);

上面的代码我们声明了一个timer的定时器和一个nums的数组,timer没有清理,nums我们明确以后不会再使用,但是timer、nums会一直存在内存中,这样就容易引起内存泄漏
常见的内存泄漏情况包括:
未及时清除的计时器:如果你创建了一个计时器,但忘记在不再需要时清除它,它将一直存在并持有对相关对象的引用,导致内存泄漏未解绑的事件监听器:如果你绑定了一个事件监听器,但在元素被销毁之前忘记解绑它,这个监听器将一直存在,并可能持有对相关对象的引用,导致内存泄漏循环引用:如果对象之间存在循环引用(例如,对象 A 持有对象 B 的引用,同时对象 B 也持有对象 A 的引用),即使它们不再被使用,垃圾回收器也无法释放它们的内存,导致内存泄漏
当内存泄漏过大时会严重影响我们的代码,因为在开发时为避免内存泄漏,可以采取以下措施:
- 尽量避免创建不必要的闭包,当不再需要时,显式地解除对闭包的引用
- 将不再使用的变量设置为 null,以协助垃圾回收
- 尽量避免循环引用,特别是在闭包中
- 仔细管理计时器、事件监听器和其他可能持有对对象的引用的机制
- 使用优化的数据结构和算法,避免不必要的内存占用
闭包
闭包是指一个函数能够访问和操作在其词法作用域以外定义的变量。闭包在JavaScript 中被广泛应用,它可以用于创建私有变量、实现模块化等。由于闭包会使函数引用外部变量,当闭包存在时,垃圾回收器可能无法释放被闭包引用的对象,导致
内存泄漏
function createIncrease() {const doms = new Array(100000).fill(0).map((item, i) => {const dom = document.createElement("div");dom.innerHTML = i;return dom;});function _temp() {return doms;}function _increase() {}return _increase;}let increase;btn.addEventListener("click", () => {increase = createIncrease();});
上面的代码当点击事件被执行时对increase重新赋值,而createIncrease方法返回_increase方法,因此,此时doms是一块无法触达的内存空间,那么此时的这块无法触达的内存空间会被回收吗?
未点击之前

点击后

从上面的图片可以看出,doms并不会被回收,这是因为_temp和_increase方法的闭包环境是一样的,它们共用一个词法环境,因此doms不会被回收
从上面的例子可以看出,闭包导致内存泄漏的原因有:
- 持有了不再需要的函数引用,会导致函数关联的词法环境无法销毁,导致内存泄漏
- 当多个函数共享词法环境时,会导致词法膨胀,从而使一些无法触达的内存空间无法回收,导致内存泄漏
相关文章:
浅谈垃圾回收、内存泄漏与闭包
什么是垃圾? 在js中,垃圾通常指的是不再被程序使用的内存或对象。也就是说,垃圾是指程序中分配的内存空间或对象,但不再被程序使用或无法被访问到的内容 function createIncrease() {const doms new Array(100000).fill(0).map((…...
2 月 7 日算法练习- 数据结构-树状数组
树状数组 lowbit 在学习树状数组之前,我们需要了解lowbit操作,这是一种位运算操作,用于计算出数字的二进制表达中的最低位的1以及后面所有的0。 写法很简单: int lowbit(int x){return x &am…...
[AIGC] 开源流程引擎哪个好,如何选型?
开源流程引擎是指一种自动化的工作流解决方案,它可以帮助你管理和协调你的业务流程和决策。但是,在开源世界里,有许多不同的流程引擎可以选择。因此,如何选择适合你的开源流程引擎,是一个具有挑战性和价值的话题。 文章…...
服务器使用过程中遇到常见故障及解决方案(包括蓝屏死机、无法删除的文件如何清理、网络卡、服务器连接不上等)
互联网时代,服务器的安全性和稳定性尤为重要,支撑着整个互联网行业的信息和数据安全。最近经常有客户咨询服务器的日常故障排除方法。由于服务器复杂的硬件结构和繁琐的运行原理,经常会出现这样那样的问题,有时即使是最小的问题也…...
【推荐算法】userid是否需要建模
看到一个din的源码,将userid也构建了emb table。 于是调研了一下。即推荐算法需要建模userid吗? 深度学习推荐算法中user-id和item-id是否需要放入模型中作为特征进行训练呢? 深度学习推荐算法中user-id和item-id是否需要放入模型中作为特…...
图解支付-金融级密钥管理系统:构建支付系统的安全基石
经常在网上看到某某公司几千万的个人敏感信息被泄露,这要是放在持牌的支付公司,可能就是一个非常大的麻烦,不但会失去用户的信任,而且可能会被吊销牌照。而现实情况是很多公司的技术研发人员并没有足够深的安全架构经验来设计一套…...
新概念英语第二册(58)
【New words and expressions】生词和短语(16) blessing n. 福分,福气 disguise n. 伪装 tiny adj. 极小的 possess v. 拥有 cursed …...
java和javascript的区别和联系
Java和JavaScript是两种非常流行的编程语言,尽管它们的名称相似,但实际上它们在设计、用途和运行环境等方面有很大的不同。以下是Java和JavaScript之间的主要区别和联系: 区别 设计目的和用途: Java 是一种通用的、面向对象的编程…...
uniapp中配置开发环境和生产环境
uniapp在开发的时候,可以配置多种环境,用于自动切换IP地址,用HBuilder X直接运行的就是开发环境,用HBuilder X发布出来的,就是生产环境。 1.使用HBuilder X创建原生的uniapp程序 选择vue3 2.什么都不改,就…...
prometheus之mysqld_exporter部署
mysql_exporter部署 下载解压压缩包 mkdir /opt/mysqld_exporter/ cd /opt/mysqld_exporter/ # 修改为自己的软件下载地址 wget http://soft.download/soft/linux/prometheus/mysqld_exporter/mysqld_exporter-0.14.0.linux-amd64.tar.gz tar -zxvf mysqld_exporter-0.14.0.…...
<网络安全>《19 安全态势感知与管理平台》
1 概念 安全态势感知与管理平台融合大数据和机器学习技术,提供可落地的安全保障能力,集安全可视化、监测、预警和响应处置于一体。它集中收集并存储客户I环境的资产、运行状态、漏洞、安全配置、日志、流量等安全相关数据,内置大数据存储和多…...
sqli靶场完结篇!!!!
靶场,靶场,一个靶场打一天,又是和waf斗智斗勇的一天,waf我和你拼啦!! 31.多个)号 先是一套基本的判断 ,发现是字符型,然后发现好像他什么都不过滤?于是开始poc 3213131…...
堆结构的解读
对于数据结构堆来说,堆事一种特定的数据结构,其与二叉树非常类似,但是又与二叉树有所不同,其不同点在于堆不需要左右指针指向孩子节点,而给定一个数组,将数组中的元素进行特定排序之后,就可以得…...
7、Qt5开发及实列(笔记)
文章目录 第二章 Qt5模板库、工具类及控件2.2 容器类2.2.1 QList类 # 2.3 QVariant类 #2.4 算法及正则表达式2.5控件 第二章 Qt5模板库、工具类及控件 2.2 容器类 2.2.1 QList类 //2.2容器类 - QList类QList<QString> list;//声明了一个QList<QString>栈对象{QSt…...
FPGA_ip_Rom
一 理论 Rom存储类ip核,Rom是只读存储器的简称,是一种只能读出事先存储数据的固态半导体存储器。 特性: 一旦储存资料,就无法再将之改变或者删除,且资料不会因为电源关闭而消失。 单端口Rom: 双端口rom: 二 Rom ip核…...
5-3、S曲线生成器【51单片机+L298N步进电机系列教程】
↑↑↑点击上方【目录】,查看本系列全部文章 摘要:本节介绍步进电机S曲线生成器的计算以及使用 一.计算原理 根据上一节内容,已经计算了一条任意S曲线的函数。在步进电机S曲线加减速的控制中,需要的S曲线如图1所示,横…...
Google开源项目风格指南——Java
Google Java Style Guide 谷歌 Java 风格指南 谷歌 Java 风格指南1 简介1.1 术语说明1.2 指导说明 2 源文件基础知识2.1 文件名2.2 文件编码:UTF-82.3 特殊字符2.3.1 空白字符2.3.2 特殊转义序列2.3.3 非ASCII字符 3 源文件结构3.1 许可或版权信息(如果存…...
数字图像处理与Python语言实现-常见图像特效(二)
文章目录 9、Splash滤镜10、双色调(Duo-Tone)滤镜11、日光(Daylight)滤镜12、60sTVs效果13、高对比度14、棕褐色/复古滤镜15、晕影效果16、模糊滤镜17、浮雕边缘9、Splash滤镜 在Splash滤镜中,仅某些颜色保持原样,其余颜色转换为灰度。 为了执行此操作,我们将在 HSV 颜…...
学习方法分享
工作上的代码实现,不要过度设计,不要想着炫技,要简单务实,“大道至简”。 学习一个方向(模块化)的知识,不经意间就会涉及到另一个领域,比如从消息队列存储的顺序读/写,延…...
Python学习路线 - Python高阶技巧 - 拓展
Python学习路线 - Python高阶技巧 - 拓展 闭包闭包注意事项 装饰器装饰器的一般写法(闭包写法)装饰器的语法糖写法 设计模式单例模式工厂模式 多线程进程、线程并行执行多线程编程threading模块 网络编程Socket客户端和服务端Socket服务端编程实现服务端并结合客户端进行测试 S…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
