首页 > 系统相关 >内存泄漏

内存泄漏

时间:2022-10-19 12:14:20浏览次数:79  
标签:泄漏 垃圾 对象 回收 算法 内存 引用

要了解内存泄漏与内存溢出,首先需要了解内存是怎么分配的,故此,本文将按照以下几节阐述:

  1. 内存管理
  2. 垃圾回收·
  3. 内存泄漏

内存管理

JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让 JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。

内存生命周期基本是一致的:

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时将其释放\归还

在JavaScript中第一步和第三步都是隐含的

为了不让程序员费心分配内存,JavaScript 在定义变量(值的初始化)时就完成了内存分配。

内存分配

var n = 123; // 给数值变量分配内存
var s = "azerty"; // 给字符串分配内存
var o = {
  a: 1,
  b: null
}; 
// 给对象及其包含的值分配内存

// 给数组及其包含的值分配内存(就像对象一样)
var a = [1, null, "abra"];

function f(a){
  return a + 2;
} 
// 给函数(可调用的对象)分配内存

// 函数表达式也能分配一个对象
someElement.addEventListener('click', function(){
  someElement.style.backgroundColor = 'blue';
}, false);

有些函数调用结果是分配对象内存:

var d = new Date(); // 分配一个 Date 对象

var e = document.createElement('div'); // 分配一个 DOM 元素

使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。

当分配的内存不再使用时释放它

大多数内存管理的问题都在这个阶段。在这里最艰难的任务是找到“哪些被分配的内存确实已经不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。

高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)。

垃圾回收

垃圾回收算法主要依赖于引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。例如,一个 Javascript 对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)。

引用计数垃圾回收

最初级的垃圾回收,此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。

限制:无法处理循环引用的事例。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。内存发生泄漏

标记清除算法

这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。

这个算法假定设置一个叫做根(root)的对象(在 Javascript 里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。

这个算法比前一个要好,因为“有零引用的对象”总是不可获得的,但是相反却不一定,参考“循环引用”。

从 2012 年起,所有现代浏览器都使用了标记 - 清除垃圾回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记 - 清除算法的改进,并没有改进标记 - 清除算法本身和它对“对象是否不再需要”的简化定义。

循环引用只要无法从根出发获得对象就会被清除

限制:无法从根对象查询到的对象都会被清除

内存泄漏

内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。(程序某个未使用的变量或者方法,长期占用内存不会释放,导致内存堆积浪费)引用计数方式对 DOM 对象进行垃圾回收。该方式常常造成对象被循环引用时内存发生泄漏

内存溢出:“内存溢出(Out Of Memory,简称OOM)是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了,系统会提示内存溢出,有时候会自动关闭软件,重启电脑或者软件后释放掉一部分内存又可以正常运行该软件,而由系统配置、数据流、用户代码等原因而导致的内存溢出错误,即使用户重新执行任务依然无法避免。”(因为某些原因,程序使用的内存大于硬件提供的内存,导致内存超出了)

————————————————

内存泄漏可能的原因

一、全局变量引用

这种问题发生的频率一般较小, 我觉得应该没人把全局变量绑定到组件上,或者使用变量没有声明。

需要注意的是,要尽可能少地声明全局变量,因为GCRoots的原因,很容易会在查看引用链的时候链接到window上的属性,造成干扰。

二、定时器未清除

如果你不确定是不是定时器导致的问题,可以打开【开发者工具】,在Chrome中会有警告

image-20210826180909995

所以养成好习惯,setTimeout使用一定要清除

const timer = setTimeOut(() => {
    this.resize()
    clearTimeOut(timer)
})
复制代码

setInterval也是一样的处理,不过不太建议在代码里使用setInterval,主要是不太好控制和错误捕获不到。

在平时开发时,可以留意下控制台里面Chrome发出的warning,去看看背后的原因是什么,一般和性能都是有关系的,这样会让你知道怎么样写代码对于浏览器来说是没有问题的。

三、事件未清除

这也是很常见的问题,养成好习惯。

// mounted
window.addEventListener('resize', this.resize)
// beforeDestory
widnow.removeEventListener('resize', this.resize)
复制代码

这里需要注意最好不要用on的方式去绑定事件,覆盖事件以及解绑处理起来会很麻烦。

四、console

生成环境最好不要有console.log,如果有,最好是文字解释或者格式化后的JSON字符串,不要引用当前实例的数据。

五、未添加到Document的dom

function download(url) {
    const a = document.createElement('a')
    a.href = url
    a.click()
}
如果不手动将a置为null,那么该dom会一直造成泄漏
复制代码

六、使用一些插件时,未销毁由该插件生成的dom

比较常用的如Sortable

const sortableInstance = Sortable.create(……)
sortableInstance.destroy()
复制代码

另外我们自己写的一些函数,如果生成了dom,或者引用了dom,都要记得销毁。

let loading = this.$loading({
 ……,
 target: this.$refs.table.el
})

……
loading.close()
loading = null

参考引用:

https://juejin.cn/post/7005110828593020965

https://blog.csdn.net/qq_36359674/article/details/123357844

标签:泄漏,垃圾,对象,回收,算法,内存,引用
From: https://www.cnblogs.com/Allerge/p/16805815.html

相关文章

  • java 内存分析优化
    MATjava内存分析工具:https://cloud.tencent.com/developer/article/1377476内存溢出问题排查:https://mp.weixin.qq.com/s/lQut5nWIT3WbuVA57bw4pw......
  • 关于内存计算的不成熟的理解
    关于内存计算的不成熟的理解说明自己其实没有做过大数据内存计算方面的工作.仅是对硬件知识有一些了解.想着简单描述一下自己所理解的内存计算.可能有多偏颇的地方.......
  • 初识内存池
    在程序开发过程中,我们总会涉及到一个概念,那就是内存管理(一般值堆内存)。一旦由内存使用和管理不当导致程序运行宕机,会发生无法预测的灾难。内存问题分析比较困难,因为大......
  • js栈内存和堆内存
    js栈内存和堆内存的区别栈(stack)会自动分配内存空间,栈内存变量基本上用完就会自动释放。堆(heap)动态分配的内存,大小不定也不会自动释放,只有当所有调用的变量全部销毁之......
  • 【备忘】Eclipse内存泄漏分析工具MAT - Memory Analyzer Tools
    下载https://www.eclipse.org/mat/downloads.phpLinux上生成HeapDump使用jdk的命令/path/to/jdk/bin/jmap-dump:format=b,file=<文件名XX.hprof><pid>为MAT配置JD......
  • 【C语言知识碎片】动态内存分配函数的使用
    1.为什么需要动态内存分配我们需要存储一些数据时可以创建一个变量或者数组来进行存储。intval=10;intarr[10]={0};数组在开辟好之后大小是不能变的,但是这种静态的内存在......
  • C#操作CPU内存时 winIO32位,64位的使用(运行时要用管理员身份)注意事项
    一、WinIo说明WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Wi......
  • String内存泄漏
    内存泄漏:指为一个对象分配好内存之后,在对象已经不再使用时未及时的释放,倒是一直占据内存单元,使实际可用内存减少,就好像内存泄漏了一样。内存溢出:内存不够用了,比如在一个无......
  • "0x00a1bdb3" 指令引用的 "0x00000001" 内存。该内存不能为 "read"。
    笔记本换成XP系统后,单击我的电脑或者别的时候,有时会提示,下面的错误提示:---------------------------IExplore.exe-应用程序错误---------------------------"0x00a1bdb3"......
  • Java内存模型(JMM)详解
    目录什么是JMM?Java运行时内存区域与硬件内存的关系Java内存区域和Java内存模型有何区别?Java线程与主内存的关系什么是主内存?什么是本地内存?线程间通信重温Java并发三......