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

news2024/11/16 11:34:06

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 + b
  return 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和someResource
        node.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、避免过度使用内包

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/356122.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 项目介绍

Spring Boot 项目介绍 作为学习过 Java 的软件开发者,相信都知道 Spring 这一伟大的框架,它所拥有的强大功能之一就是可以集成各种开源软件。但随着互联网的高速发展,各种框架层出不穷,这就对系统架构的灵活性、扩展性、可伸缩性…

【项目精选】基于JSP物流信息网(论文+源码+视频)

点击下载源码 近年来,随着时代的进步,社会随之不断发展,经济也快速发展起来了,人民的消费水平在不断地提高,平常的实体店消费已经不能满足人们的需求;在者,互联网技术的不断发展也为电子商务的兴…

CSS Houdini

前言 最近看了几篇文章,是关于 CSS Houdini 的。作为一个前端搬砖的还真不知道这玩意,虽然不知道的东西挺多的,但是这玩意有点高大上啊。 Houdini 是一组底层 API,它们公开了 CSS 引擎的各个部分,从而使开发人员能够通…

Matlab搭建AlexNet实现手写数字识别

Matlab搭建AlexNet实现手写数字识别 个人博客地址 文章目录Matlab搭建AlexNet实现手写数字识别环境内容步骤准备MNIST数据集数据预处理定义网络模型定义训练超参数网络训练和预测代码下载环境 Matlab 2020aWindows10 内容 使用Matlab对MNIST数据集进行预处理,搭建…

基于Spring Boot框架的人事管理系统的设计与实现(程序+详细文档)

大家好✌!我是CZ淡陌。这里为大家分享优质的实战项目,本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目,希望你能有所收获,少走一些弯路! 🍅更多优质项目👇&am…

面向六部十层电梯群控算法的研究

面向六部十层电梯群控算法的研究 赵大权,张翔宇 (晋中学院 机械学院,山西 晋中 030619) 摘 要: 在商业大楼和高层写字楼里,基于可编程逻辑控制器(PLC)对电梯运行进行控制是当前主流…

【LeetCode】剑指 Offer(4)

目录 写在前面: 题目:剑指 Offer 10- I. 斐波那契数列 - 力扣(Leetcode) 题目的接口: 解题思路: 代码: 过啦!!! 题目:剑指 Offer 10- II. …

河南工程学院2.17蓝桥杯培训

乘法口诀数列:https://www.acwing.com/problem/content/3466/ 剪绳子:https://www.acwing.com/problem/content/68Sin SinSine之舞:http://lx.lanqiao.cn/problem.page?gpidD5272 数列:https://www.acwing.com/problem/content/…

【郭东白架构课 模块一:生存法则】13|法则六:如何鉴别文化环境是否有利于架构师的生存?

你好,我是郭东白。 架构师通常并不管理团队,而是管理架构活动。更准确地说,是定义和引导架构活动。因为每个参与架构活动的个体,都有各自工作的优先级和汇报关系。因此在没有管理、考核和激励等手段的保障下,唯一能够…

Chrome 又不支持 HTTP/2 网站的原因

导读昨晚偶尔清理 Chrome 插件时发现我的 “HTTP/2 and SPDY indicator”插件好像好久没亮了。这个插件在你访问到一个支持 HTTP/2 (或之前的 SPDY 协议)的网站时会点亮,而我明明记得之前专门让 https://linux.cn/ 支持了 HTTP/2 。 我的第一…

软考高级-信息系统管理师之整体管理(最新版)

整体管理 1、项目整体管理概述2、制定项目章程(选择,案例,论文)制定项目章程过程制定项目章程的依据1、协议2.项目工作说明书:3、商业论证4、事业环境因素包括,但不限于如下事项。5、组织过程资产:项目选择方法项目启动会议项目目标引导技术3、制订项目管理计划(选择)项目管…

MakeFile编写 使用

目录 1、基本格式如下:2、GCC编译过程3、Makefile具体流程可参考下图:4、Makefile变量解析![在这里插入图片描述](https://img-blog.csdnimg.cn/50fdafadef79400abea65b64a12f8ec8.png)5、实例项目目录5.1 使用g直接编译5.2 Version 15.3 Version 25.4 V…

[oeasy]python0086_ASCII_出现背景_1963年_DEC_PDP系列主机_VT系列终端

编码进化 回忆上次内容 上次 回顾了 字符编码的新陈代谢 ibm 曾经的EBCDIC 由于 字符不连续导致 后续 出现无数问题 随着 网络的发展 数据交换的 需要原来的小隐患现在 产生了 巨大问题 Bemer 联合各方巨头 想要推出 字符连续的编码集 这新编码集 具体长什么样 呢&#xff1…

springmvc绿植培养交流平台java的ssm设计与实现

本绿植培养交流平台设计与实现以SSM作为框架,B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块:个人中心、用户管理、品种类型管理、绿植信息管理、视频分类管理、视频信息管理、经验交流、系统管理等模块,通过这些模块的实…

Java之动态规划之机器人移动

目录 0.动态规划问题 一.不同路径 1.题目描述 2.问题分析 3.代码实现 二.不同路径 II 1.题目描述 2.问题分析 3.代码实现 三.机器人双向走路 1.题目描述 2.问题分析 3.代码实现 0.动态规划问题 动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问…

九龙证券|连续七周获加仓,四大行业成“香饽饽”!

本周17个申万职业北上资金持股量环比增加。 北上资金抢筹铝业龙头 本周A股商场全体冲高回落,沪指收跌1.12%,深成指跌2.18%,创业板指跌3.76%。北上资金周内小幅净流入。在大盘体现较差的周四周五,北上资金别离逆市回流67.94亿元、…

Vue项目创建首页发送axios请求

这是个全新的Vue项目,引入了ElementUI 将App.vue里的内容干掉,剩如下 然后下面的三个文件也可以删掉了 在views文件下新建Login.vue组件 到router目录下的index.js 那么现在的流程大概是这样子的 启动 写登陆页面 <template><div><el-form :ref"form"…

blackduck issue fix

文章目录场景依赖包风险扫描插件——synopsys codesight安装其他工具snyk公司提供/允许的工具指定依赖版本场景 你在一个前端nodejs项目中使用到了好多个依赖包&#xff0c;其中某几个依赖包的某些版本是有风险的。 在项目上线前&#xff0c;你最好修复这些安全风险。这时&…

SVN 获取多版本间的更新内容

文章目录背景介绍操作步骤 - 获取某段时间内的代码更新内容背景介绍 公司有个项目期初明确要做微信小程序&#xff0c;没有做其他端的意向&#xff0c;并且当时团队人数有限&#xff0c;没有项目实践过 uniapp&#xff0c;项目时间周期紧&#xff0c;就没有用 uniapp 去实现 然…

Linux架设魔兽争霸3战网Battle.net私服

文章目录 用到的工具pvpgnpvpgn-support-1.2Warcraft 3 Loader for PvPGNBNetEditor.exe搭建服务端魔兽争霸3登录战网私服添加战网服务器地址使用Warcraft 3 Loader启动魔兽争霸3工具下载用到的工具 pvpgn PvPGN是一款免费开源的跨平台服务器软件,支持Battle.net和Westwood …