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

JavaScript内存泄露和垃圾回收机制

1、是什么?

内存泄露(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存。并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费

对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,造成应用程序卡顿或崩溃,轻则影响系统性能,重则导致进程崩溃。

2、垃圾回收机制

JavaScript具有自动垃圾回收机制(Garbage Collection),即执行环境会负责管理代码执行过程中使用的内存。

原理垃圾收集器会定期(周期性)找出那些不再继续使用的变量,然后释放其内存。

两种方式:

(一)标记清除--JavaScript最常用的垃圾回收机制

当变量进入环境时,就标记这个变量为”进入环境“。进入环境的变量所占用的内存就不能释放,当变量离开环境时,则标记为”离开环境“。

垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它将所有在上下文中的变量、以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并回收它们的内存。

var m = 0,n = 19 // 把 m,n,add() 标记为进入环境。
add(m, n) // 把 a, b, c标记为进入环境。
console.log(n) // a,b,c标记为离开环境,等待垃圾回收。
function add(a, b) {a++var c = a + breturn c
}

(二)引用计数

语言引擎有一张”引用表“,保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放。

如果一个值不再需要了,引用次数却不为0.垃圾回收机制无法释放这块内存,从而导致内存泄露。

例如:

const arr = [1, 2, 3, 4];

console.log('hello world');

//数组[1, 2, 3, 4]是一个值,会占用内存。变量arr是仅有的对这个值的引用,因此引用次数为1。尽管后面的代码没有用到arr,它还是会持续占用内存。如果需要这块内存被垃圾回收机制释放,只需要设置如下:

arr=null

//通过设置arr为null,就解除了对数组[1,2,3,4]的引用,引用次数为0,就被垃圾回收了

小结:有了垃圾回收机制,不代表不用再关注内存泄露。那些很占空间的值,一旦不再用到,需要检查是否还存在对它们的引用,如果是的话,则必须手动解除。

3、常见内存泄露情况

定时器、函数闭包、没有清理对DOM元素的引用、使用事件监听addEventListener监听的时候,再不监听的时候使用removeEventListener取消对事件的监听。

意外的全局变量:

function foo(arg){bar='this is a hidden global variable'
}

由this创建的全局变量:

function foo(){this.variable='potential accidental global variable'
}
foo()//foo调用自己,this指向了全局对象(window)

这两种情况可以通过使用严格模式(use strict)避免意外的全局变量。

定时器:

var someResource=getData()
setInterval(function(){var node=document.getElementById('Node')if(node){//处理node和someResourcenode.innerHTML=JSON.stringify(someResource)}
,1000)
如果id为Node的元素从DOM中移除,该定时器仍会存在,同时因为回调函数中包含对someResource的引用,定时器外面的someResource也不会被释放

闭包:

function bindEvent(){var obj=document.createElement('XXX')var unused=function(){console.log(obj,'闭包内引用obj obj不会被释放')}obj=null//解决方法
}
var foo=bindEvent()
//理论上说,bindEvent()函数内部定义的变量应当在执行完bindEvent之后就销毁,但是foo引用了bindEvent方法,按照引用计数法,是不会回收bindEvent内部定义的变量的,这就会造成内存泄露。

没有清理对DOM元素的引用同样造成内存泄露:

const refA=document.getElementById('refA')
document.body.removeChild(refA)//dom删除了refA元素
console.log(refA,'refA')//引用refA,打印出整个dom元素
refA=null
console.log(refA,'refA')//解除引用const wrapDOM = document.getElementById('wrap');
wrapDOM.onclick = function (e) {console.log(e);};// some codes ...// remove wrapDOM
wrapDOM.parentNode.removeChild(wrapDOM);

4、内存泄露的排查手段

Chrome浏览器打开F12,开始记录Performance查看js堆内存占用信息:

点击Stop停止录制。

选中JS Heap,下面展现出来的一条蓝线,就是代表了这段记录过程中,JS 堆内存信息的变化情况。

如果蓝线一直呈上升趋势,那么说明有很多未被释放的内存。至于这些内存是否泄露还是在使用,需要进一步排查。

Memory精确定位内存使用情况,点击按钮生成应用在当前时刻的内存快照信息。

当生成第一个快照的时候,开发者工具窗口显示了很详细的内存占用情况:

Constructor:占用内存的资源类型。

Distance:当前对象到根的引用层级距离

Shallow Size:对象所占内存(不包含内部引用的其它对象所占的内存)(单位:字节)

Retained Size:对象所占总内存(包含内部引用的其他对象所占的内存)(单位:字节)

每项展开就可以查看更详细的数据信息。可以再次切回网页,继续操作几次,然后再次生成一个快照:

选择Comparison可对两次快照进行更详细的比对:

#New:新分配的内存空间数

#Deleted:销毁的内存空间数

#Delta:内存回收差值=新分配-销毁,如果是正值,代表新生成的内存多,释放的内存少。其中的闭包closure项如果是正值,说明存在内存泄露

5、内存泄露的解决办法

5.1、使用严格模式,避免不经意间的全局变量泄露:

use strict
function foo(){b=2
}
foo()// ReferenceError: b is not defined

5.2、关注DOM生命周期,及时销毁DOM

const wrapDOM = document.getElementById('wrap');
wrapDOM.onclick = function (e) {console.log(e);};// some codes ...// remove wrapDOM
wrapDOM.onclick = null;
wrapDOM.parentNode.removeChild(wrapDOM);

或者可以使用事件委托的手段统一处理事件,减少由于事件绑定带来的额外内存开销:

document.body.onclick = function (e) {if (isWrapDOM) {// ...} else {// ...}
}

5.3、避免过度使用内包

大部分的内存泄漏还是由于代码不规范导致的。代码千万条,规范第一条,代码不规范,开发两行泪。

相关文章:

JavaScript内存泄露和垃圾回收机制

1、是什么?内存泄露(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存。并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内…...

Kubernetes02:知识图谱

Kubernetes01:知识图谱 MESOS APACHE 分布式资源管理框架 2019-5 Twitter 》 Kubernetes Docker Swarm 2019-07 阿里云宣布 Docker Swarm 剔除 Kubernetes Google 10年容器化基础架构 borg Go语言 Borg 特点 轻量级:消耗资源小 开源 弹性伸缩 负载均…...

nginx-服务器banner泄漏风险

http { server_tokens off; # 隐藏Nginx版本号 .... }...

GCC 同名符号冲突解决办法

一、绪论 作为 C/C 的开发者,大多数都会清楚课本上动态库以及静态库的优缺点,在教科书上谈及到动态库的一个优点是可以节约磁盘和内存的空间,多个可执行程序通过动态库加载的方式共用一段代码段 ;而时至今日,再看看上…...

下一代视频编码技术2023

下一代视频编码技术 下面将从这两个角度来介绍华为云视频在下一代视频编码技术上的一些工作。这些技术得益于华为2012 媒体技术院全力支持。 2.1 下一代视频编码标准技术 从上图可以看出,下一代的视频编码标准大概分为三个阵营或者三个类型: 国际标准…...

最新最全中小微企业研究数据:海量创业公司信息与获取投资信息(1985-2021年)

一、企业获取投资名单&资方信息 数据来源:搜企网、企查查、天眼查 时间跨度:1985年8月-2021年9月 区域范围:全国范围 数据字段:企业名称、时间、获得投资金额以及投资方信息 部分数据: DateCompany_nameUnit…...

springboot数据源浅析

DataSourceAutoConfiguration分析 SpringBoot有一个自动配置DataSourceAutoConfiguration 为数据源配置 /META-INF/spring.factories文件找到DataSourceAutoConfiguration配置类 一、先来看下DataSourceAutoConfiguration配置类生效的时机,观察源码发现 Configura…...

2022黑马Redis跟学笔记.实战篇(七)

2022黑马Redis跟学笔记.实战篇 七4.11.附近的店铺功能4.11.1. GEO数据结构的基本用法1. 附近商户-导入店铺数据到GEO4.11.2. 获取附近的店铺1. 附近商户-实现附近商户功能4.9. 签到功能4.9.1.BitMap原理1. 用户签到-BitMap功能演示4.9.2.实现签到功能4.9.3.实现补签功能4.9.4.统…...

QT mp3音乐播放器实现框架,Qt鼠标事件,网络编程,QSqlite,Json解析,HTTP请求等

QT mp3音乐播放器实现框架,Qt鼠标事件,网络编程,QSqlite,Json解析,HTTP请求等框架搭建UI设计mp3.hmp3.cpp隐藏窗口标题 最大化 最小化 关闭框架搭建 .pro添加 # 网络 添加多媒体 数据库 QT network multimedia sql添加头…...

硬件学习 软件Cadence day04 PCB 封装绘制

1.文章内容: 1. 贴片式电容 PCB 封装绘制 (型号 c0603 ) 2. 贴片式电阻 PCB 封装绘制 (型号 r0603 ) 3. 安规式电容 PCB 封装绘制 (这个就是 有一个电容,插入一个搞好的孔里面 …...

【Java】yield()和join()区别

一、java 线程调度的背景 java虚拟机要求在多线程中实现 preemptive和priority-based调度,这意味着java中每一个线程被分配了特定的优先级,正整数在定义好的范围内不断减。优先级可以通过开发者改变但是java虚拟机从不改变线程的优先级,即使…...

【MySQL】Java连接MySQL数据库(封装版只需会MySQL)

一、准备普通项目如果创建的是普通的Java项目,我们需要去maven仓库下载jdbc驱动包然导入项目中就能使用,具体步骤详见MySQL数据库之Java中如何使用数据库【JDBC编程】maven项目如果创建的项目是maven项目,我们只需在pom.xml文件里引入一组依赖…...

【java基础】运算符

运算符 operator 运算符优先级 Operators 操作员Precedence 优先级postfix 后缀expr expr--unary 一元的expr --expr expr -expr ~ !multiplicative 〔数〕乘法的 / %additive 添加剂 -shift 移动<< >> >>>relational 关系的< > < > insta…...

带噪学习-概述

在实际应用的时候&#xff0c;我们的样本不会是完全干净的&#xff0c;即存在噪声样本。那使用存在噪声的样本时&#xff0c;我们如何更有效的进行模型学习呢&#xff1f;Label Dependent Nose样本选择&#xff08;Sample Selection&#xff09;第一种很直接的想法&#xff0c;…...

Scratch少儿编程案例-多彩打地鼠

专栏分享 点击跳转=>Unity3D特效百例点击跳转=>案例项目实战源码点击跳转=>游戏脚本-辅助自动化点击跳转=>Android控件全解手册点击跳转=>Scratch编程案例👉关于作者...

为什么拔掉计算机网线还能ping通127.0.0.1?

前言 当我们在计算机上拔掉网线之后&#xff0c;发现我们仍然可以使用ping命令来ping通本机的IP地址127.0.0.1&#xff0c;这让很多人感到困惑&#xff0c;认为拔掉网线后计算机就无法与外界通信了&#xff0c;为什么还能ping通本机的IP地址呢&#xff1f; 本文的目的是通过对…...

Android kotlin 内、外部存储根目录及测试(可以实现仿微信未读消息数提示数字)

<<返回总目录 文章目录 一、内部存储与外部存储三、外部存储的写读测试(可以实现仿微信未读消息数提示数字)一、内部存储与外部存储 所有Android设备都有两个文件存储区域:内部存储空间(internal Storage)和外部存储空间(external Storage)。所以,Android系统从逻…...

Android 7.0 OTA升级(高通)

文章目录1. Full OTA 方式升级介绍1.1 Full OTA 制作第一步&#xff1a;生成 msm89xx-target_files-eng.XXX.zip1.2 Full OTA 制作第二步&#xff1a;Modem 等非 HLOS 加入升级包的方法1.3 Full OTA 制作第三步&#xff1a;生成 update.zip 升级包2. Incremental OTA 方式升级介…...

工作负载之DeployMent

DeployMent 无状态工作负载&#xff08;Deployment&#xff09;&#xff1a;即kubernetes中的“Deployment”&#xff0c;无状态工作负载支持弹性伸缩与滚动升级&#xff0c;适用于实例完全独立、功能相同的场景&#xff0c;如&#xff1a;nginx、wordpress等。 也是公司中应…...

淘宝tmall页面数据获取,API接口对接程序

item_get-获得淘宝商品详情请求参数请求参数&#xff1a;num_iid652874751412&is_promotion1参数说明&#xff1a;num_iid:淘宝商品IDis_promotion:是否获取取促销价响应参数Version: Date:2022-04-04名称类型必须示例值描述itemitem[]1宝贝详情数据num_iidBigint152081325…...

企业SEO优化如何与移动端优化协同发展_企业SEO优化的结果如何持续维护和改进

企业SEO优化如何与移动端优化协同发展 在当前数字化时代&#xff0c;企业SEO优化和移动端优化是两大关键领域&#xff0c;它们共同作用于企业的在线表现和用户体验。如何让这两者协同发展&#xff0c;已经成为企业数字营销策略中不可或缺的一部分。 企业SEO优化与移动端优化的…...

组播技术讲解

组播基础知识: 组播属于D类地址范围:224.0.0.0~240.255.255.255 图1:站在客户端的角度来看,存在两个模型ASM(任意源组播地址)、SSM(指定源组播地址);如果客户端程序只能选择加入的组地址,而无法选择组播源的地址,则部署ASM模型;如果客户端既可以选择加入的组地址,…...

NVIDIA Profile Inspector深度调校指南:释放专业显卡潜能的非游戏应用方案

NVIDIA Profile Inspector深度调校指南&#xff1a;释放专业显卡潜能的非游戏应用方案 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 在专业计算领域&#xff0c;NVIDIA Profile Inspector不仅是游戏玩…...

保姆级教程:在ROS Melodic下,用TEB局部规划器搞定阿克曼小车Gazebo自主导航(附避坑指南)

阿克曼小车Gazebo仿真与TEB局部规划器深度实战指南 当你在Gazebo中看到阿克曼转向结构的小车优雅地绕过障碍物&#xff0c;精准停靠在目标点时&#xff0c;那种成就感是难以言喻的。不同于差速驱动机器人&#xff0c;阿克曼结构的运动学特性为导航栈配置带来了独特挑战。本文将…...

影墨·今颜模型Win11/Win10系统UI风格适配与生成测试

影墨今颜模型Win11/Win10系统UI风格适配与生成测试 最近在折腾桌面美化&#xff0c;突然冒出一个想法&#xff1a;现在AI生成图片这么厉害&#xff0c;能不能让它直接帮我生成一套风格统一的系统UI元素呢&#xff1f;比如Win11那种清爽现代的图标&#xff0c;或者Win10那种经典…...

5个PathPicker高级技巧:掌握$F令牌与自定义命令的终极指南

5个PathPicker高级技巧&#xff1a;掌握$F令牌与自定义命令的终极指南 【免费下载链接】PathPicker PathPicker accepts a wide range of input -- output from git commands, grep results, searches -- pretty much anything. After parsing the input, PathPicker presents …...

百川2-13B-4bits量化模型+OpenClaw:低成本自动化办公方案实测

百川2-13B-4bits量化模型OpenClaw&#xff1a;低成本自动化办公方案实测 1. 为什么选择量化模型OpenClaw组合 去年我接手了一个需要处理大量邮件的项目&#xff0c;每天要花3小时在重复性回复上。当我尝试用OpenClaw自动化流程时&#xff0c;发现原版大模型的显存占用让我的R…...

TBPubSubClient:嵌入式MQTT轻量客户端深度解析

1. TBPubSubClient 项目概述TBPubSubClient 是一个面向嵌入式物联网终端的轻量级 MQTT 客户端库&#xff0c;专为资源受限的微控制器平台设计。该项目源自 Nick OLeary 维护的经典 PubSubClient 库&#xff08;2020 年主仓库停止更新&#xff09;&#xff0c;由 ThingsBoard 团…...

嵌入式 AI 助手的三层意图识别架构:如何在“快、准、稳“之间取得平衡

背景 我在开发一个项目协同平台的嵌入式 AI 助手。它不是独立的 chatbot&#xff0c;而是嵌在业务页面里的——用户可以在首页、项目详情页、任务抽屉等不同位置唤起它&#xff0c;用自然语言完成任务查询、创建、删除等操作。 和通用对话 AI 不同&#xff0c;这个助手有两个硬…...

GX Works2编程避坑指南:PLC数据传输指令(MOV/FMOV/BMOV)的5个常见错误与正确写法

GX Works2编程避坑指南&#xff1a;PLC数据传输指令的5个致命陷阱与工业级解决方案 在自动化产线的深夜调试现场&#xff0c;一个看似简单的MOV指令错误可能导致整条生产线异常停机——这种场景对PLC工程师来说绝不陌生。三菱GX Works2作为工业控制领域的标杆软件&#xff0c;其…...