JS的内存泄露及处理方式

2023-11-17

概念

    应用程序不再需要占用内存的时候,由于某些原因,内存没有被操作系统或可用内存池回收,就叫做内存泄漏(memory leak)

内存的生命周期

  1. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存
var a = 20        // 在内存中给数值变量分配空间   (JavaScript在定义变量时就完成了内存分配)
console.log(a + 100)   // 使用内存
var a = null      // 使用完毕之后,释放内存空间

垃圾回收机制

对垃圾回收算法来说,核心思想就是如何判断内存已经不再使用了

方法一 :引用计数法(reference counting)

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

const arr = [1, 2, 3, 4]
// 数组[1, 2, 3, 4]是一个值,会占用内存。变量arr是仅有的对这个值的引用,因此引用次数为 1
// 尽管后面的代码没有用到arr,它还是会持续占用内存
arr = null
// arr重置为null,就解除了对[1, 2, 3, 4]的引用,引用次数变成了0,内存就可以释放出来了

方法二 :标记清除法(mark-and-sweep),有三个步骤 :

  1. 垃圾回收器生成一个根列表。根通常是将引用保存在代码中的全局变量。在JavaScript中,window对象是一个可以作为根的全局变量。
  2. 所有的根都被检查和标记成活跃的(不是垃圾),所有的子变量也被递归检查。所有可能从根元素到达的都不被认为是垃圾。
  3. 所有没有被标记成活跃的内存都被认为是垃圾。垃圾回收器就可以释放内存并且把内存还给操作系统。

常见的内存泄漏情况

  1. 全局变量引起的内存泄漏
function fn() {
	num = 123   // 未声明的隐式变量等同于  window.num (全局变量)
}

// 调用完了函数以后,变量仍然存在,导致泄漏
function Fn() {
	this.num = 123    // this 指向了全局对象(window)
}

// 没有对象调用Fn,也没有给它绑定this, 因此this指向window 

注意: 如果必须使用全局变量存储大量数据时,确保用完以后把它设置为 null 或者重新定义

  1. 闭包引起的内存泄露
function outFn() {
	var num = 123    // 被闭包所引用的变量,不会被回收
	return function() {
		console.log(num)
	}
}
// 调用完了函数以后,变量仍然存在,导致泄漏
  1. 被遗忘的定时器或回调
var serverData = loadData()
setInterval(function() {
	var renderer = document.getElementById('renderer')
	if(renderer) {
		renderer.innerHTML = JSON.stringify(serverData)
	}
}, 5000) 
  1. dom清空或删除时,事件未清除导致的内存泄漏
<div id="container">  
</div>

$('#container').bind('click', function(){
    console.log('click');
}).remove();

$('#container').bind('click', function(){
    console.log('click');
}).off('click').remove();

//把事件清除了,即可从内存中移除
  1. 反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)
for(i = 0; i < 5000; i++) { 
	hostElement.text = "asdfasdfasdf"; 
} 
// 这种方式相当于定义了5000个属性

for(var i = 0; i < 5000; i++) { 
	hostElement.text = "asdfasdfasdf"; 
} 
// 把 i 声明一下

内存泄露如何避免

  1. 注意程序逻辑,避免“死循环”之类的
  2. 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收
  3. 避免创建过多的对象 原则:不用了的东西要及时归还

内存泄漏的识别方法

一、浏览器

  1. 打开开发者工具,选择 Timeline 面板
  2. 在顶部的Capture字段里面勾选 Memory
  3. 点击左上角的录制按钮。
  4. 在页面上进行各种操作,模拟用户的使用情况。
  5. 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。

二、命令行

    命令行可以使用 Node 提供的process.memoryUsage方法

console.log(process.memoryUsage());
// { rss: 27709440,
//  heapTotal: 5685248,
//  heapUsed: 3449392,
//  external: 8772 }

    process.memoryUsage返回一个对象,包含了 Node 进程的内存占用信息。该对象包含四个字段,单位是字节,含义如下:

  • rss(resident set size):所有内存占用,包括指令区和堆栈。
  • heapTotal:"堆"占用的内存,包括用到的和没用到的。
  • heapUsed:用到的堆的部分。
  • external: V8 引擎内部的 C++ 对象占用的内存。

    判断内存泄漏,以heapUsed字段为准。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JS的内存泄露及处理方式 的相关文章

随机推荐

  • eclipse导入后将普通项目变为java项目

    eclipse用subclipse导入svn项目时 没有选择项目类型 这样就不能修改项目的buildpath no action aviliable 打开workspace下面的 projcet文件在标签
  • SparkSQL HiveSQL 常用正则表达式

    SparkSQL HiveSQL 常用正则表达式 目录 SparkSQL HiveSQL 常用正则表达式 1 匹配汉字 2 匹配手机号码 3 匹配身份证 4 SparkSQL HiveSQL 常用正则函数 5 SparkSQL 分组 聚合
  • 期待2021!

    好久没写文章了 甚至好久没有看文章了 要说这些天怎么过去了呢 恍恍惚惚 竟一时语塞 恍惚着 这2020竟马上过去了 好多好多人都写了分享了自己的年终总结 看了一些 大家好像都很有收获 再想想自己 也不能说没有任何收获 但是说不出来 最大的收
  • docker镜像服务器间复制

    概述 我们制作好镜像后 有时需要将镜像复制到另一台服务器使用 能达到以上目的有两种方式 一种是上传镜像到仓库中 本地或公共仓库 但是另一台服务器很肯能只是与当前服务器局域网想通而没有公网的 所以如果使用仓库的方式 只能自己搭建私有仓库 这会
  • SpringBoot+Dubbo分布式SOA项目骨架搭建(二)

    SpringBoot Dubbo分布式SOA项目骨架搭建 项目介绍 本项目是来自于上一篇文章http blog csdn net songxinjianqwe article details 77478385 中的服务化拆分这个部分 经过一
  • QSplitter(分离器或分隔符)

    QSplitter 分离器或分隔符 本文为原创文章 转载请注明出处 或注明转载自 黄邦勇帅 原名 黄勇 本文出自本人原创著作 Qt5 10 GUI完全参考手册 网盘地址 https pan baidu com s 1iqagt4SEC8PU
  • 顺序表的原理与初始化

    顺序表是简单的一种线性结构 逻辑上相邻的数据在计算机内的存储位置也是相邻的 可以 快速定位第几个元素 中间不允许有空值 插入 删除时需要移动大量元素 顺序表的三个要素 用 elems 记录存储位置的基地址 分配一段连续的存储空间 size
  • crontab的使用方法介绍

    使用crontab你可以在指定的时间执行一个shell脚本或者一系列Linux命令 例如系统管理员安排一个备份任务使其每天都运行 安装 apt get install cron 服务器环境下默认都会安装 使用 crontab e 进入编辑页
  • java常见面试题及答案 11-20(JVM)

    11 JVM内存分哪几个区 每个区的作用是什么 java虚拟机主要分为以下一个区 方法区 1 有时候也成为永久代 在该区内很少发生垃圾回收 但是并不代表不发生GC 在这里进行的GC主要是对方法区里的常量池和对类型的卸载 2 方法区主要用来存
  • 安全测试初体验-XSS

    XSS XSS攻击成功后 攻击者能够对用户当前浏览器的页面植入恶意脚本 通过恶意脚本 控制用户的浏览器 这些用以完成各种具体功能的恶意脚本 被称为 XSS Payload XSS Payload实际上就是JavaScript脚本 所以任何J
  • JS逆向之某头条jsvmp逻辑层算法分析

    今天我们来研究下 某头条的jsvmp逻辑层加密算法 其主要的目的是想在大家在接触此类算法时 给出点实质性的建议和思路 0x01 分析加密 进入到目标网站通过分析请求会发现一个动态的 signature 加密参数 0x02 定位加密 不同于以
  • 在matlab中编译C++和opencv

    1 在matlab中运行 mex setup命令 选择C 类型 2 运行mex build 此时matlab配置基本完成 3在VS中添加matlab中的库目录和头文件目录 附加库目录 matlab安装目录下面的 extern lib win
  • 【Docker】 使用Docker-Compose 搭建基于 WordPress 的博客网站

    引 本文将使用流行的博客搭建工具 WordPress 搭建一个私人博客站点 部署过程中使用到了 Docker MySQL 站点搭建完成后经行了发布文章的体验 WordPress WordPress 是一个广泛使用的开源内容管理系统 CMS
  • 报告老师!AICA 学员交作业了!

    关注 飞桨PaddlePaddle 公众号 获取更多技术内容
  • linux-ssh安全策略(sshd)

    实际使用中 为限制ssh高危端口我们一般做以下策略 1 修改端口 ssh默认用22 2 密码强口令 3 root限制 4 新增ssh登录白名单 5 开启端口防火墙 6 有条件的话整个密钥登录更安全 不过avatar目前不支持密钥登录 所以项
  • 最安全的加密算法

    在密码学里 有一种理想的加密方案 叫做一次一密乱码本 one time pad one time pad的算法有以下要求 1 密钥必须随机产生2 密钥不能重复使用3 密钥和密文的长度是一样的 one time pad是最安全的加密算法 双方
  • “汉堡+奶昔”怎么就成了精致生活的热门标签?

    图片来源 视觉中国 文章来源 DT财经 左手汉堡 右手奶昔 这是新天地Coco的时髦新日常 最近沪上刮起一阵打卡新风潮 汉堡竟然成了标记城市美好生活的一大利器 还在纠结晚餐去金拱门还是汉堡王的DT君 发现自己在吃汉堡这件事上竟然也要被划出潮
  • 一步一步教你怎样给Apache Spark贡献代码

    本文将教大家怎样用10个步骤完成给Apache Spark贡献代码这个任务 到 Apache Spark 的github 页面内点击 fork 按钮 你的github帐户中会出现 spark 这个项目 本地电脑上 使用 git clone
  • 用python开发了一个绘制股票k线图的工具,还可以预测股票涨跌!【文末附源码和教学视频】

    文章目录 聊一聊这个工具 效果展示 股票数据 运行项目 前端界面 后端接口 源码地址 聊一聊这个工具 起初 我并不在意echarts 这不过是一个偶然 一次选择 一条简单的代码 一个图表的诞生 直到我完成了K线图的绘制 股票 一个神奇的发明
  • JS的内存泄露及处理方式

    概念 应用程序不再需要占用内存的时候 由于某些原因 内存没有被操作系统或可用内存池回收 就叫做内存泄漏 memory leak 内存的生命周期 内存分配 当我们声明变量 函数 对象的时候 系统会自动为他们分配内存 内存使用 即读写内存 也就