常见的内存泄漏以及解决方案

一、什么是内存泄漏?

二、JS引起内存泄漏的原因?

  意外的全局变量

  闭包引用的内存泄漏

  Dom元素的引用没有被释放

  被遗忘的定时器或者回调函数

三、Vue中引起内存泄漏的原因

  全局变量引起的内存泄漏

  监听在window/body等事件没有解绑

  绑在EventBus的事件没有解绑

一、什么是内存泄漏?

  系统进程不再用到的内存,没有及时的释放,就叫做内存泄漏。

二、JS引起内存泄漏的原因?

1、意外的全局变量

  由于js对没有进行申明的变量会默认是在全局变量上定义的,而系统的全局变量是 window,只有关闭窗口和刷新页面,全局变量才会被释放,如果在一个没有声明的变量上保存了大量的数据,这些数据就会保存在全局变量上,当这些数据没有及时的被回收,就会发生 内存泄漏

  • 没有声明的变量
    function fn(){
      a='hello'
    }
    fn();
  • 使用this申明的变量
    function fn(){
     // 这里的this指向它的调用者,他的调用者是window 
      this.a='hello';
    }
    fn()

  解决方法:
  避免使用没有声明的变量;

  使用 严格模式,在js文件头部或者是函数首行使用严格模式

2、闭包引用的内存泄漏

   由于闭包可以访问函数内部的变量,让这些变量一直保存在内存中,如果没有及时的清理掉这些变量,就会发生内存泄漏。

function fn(){
  var a='i am a';
  return function(){
    console.log(a);
  }
}

  解决方法:将事件处理程序定义在函数的外部

// bad
for(var k=0;k<10;k++){
  var t=function(a){
    console.log(a)
  }
  t(k)
}

// good
function t(a){
  console.log(a)
}
for(var k=0;k<10;k++){
  t(k)
}
t=null

3、Dom元素的引用没有被释放

   虽然在别的地方Dom别删除了,但是对象对这个Dom元素的引用并没有被删除

var element={
  btn:document.getElementById('btn')
}

function doSomeThing(){
  element.btn.cilck()
}

function removeClick(){
  // 虽然移除了dom中的btn元素,但是对象中对btn的引用还是没有被删除
   document.body.removeChild(document.getElementById( 'btn' ))

  解决方法:将element.btn=null

4、被遗忘的定时器或者回调函数

   定时器中有dom的引用,即使dom删除了,但是定时器还在,所以内存中还是会有这个dom。

// 定时器模式
var data=load()
setTimeout(() => {
  var text=document.getElementById('text')
  if(text){
    text.innerHtml=JSON.stringify(data)
  }
}, 5000);

// 观察者模式
var btn=document.getElementById('btn')
function click(element){
  element.innerHtml='hello'
}
btn.addEventListener("click",click);

  解决方法:

  • 手动删除定时器和dom
  • 添加removeEventListener

三、Vue中引起内存泄漏的原因

   使用VUE开发的SPA应用,更需要关注内存泄漏,因为VUE项目是不会刷新页面的,所以 Vue 应用需要自行清理组件来确保垃圾回收以预期的方式生效。

1、全局变量引起的内存泄漏

  全局变量在页面切换的时候没有被清空。

export default {
   mounted() {
     window.test = {
       // 此处在全局window对象中引用了本页面的dom对象
       name:  home ,
       node: document.getElementById( home ),
     }
   },
 }

  解决方法:在页面卸载的时候就将全局变量被清空

2、监听在window/body等事件没有解绑

   特别注意window.addEventListener之类的事件监听

<template>
 <div id='home'>这里是首页</div>
</template>
<script>
 export default{
   mounted(){
     window.addEventListener(resize,this.func) // window对象调用了home页面的方法
   }
 }
</script>

  解决方法:在页面销毁的时候,顺便解除应用,释放内存

mounted(){
  window.addEventListener(resize,this.func)
}
beforeDestory(){
  window.removeEventListener(resize,this.func)
}
原文地址:https://www.cnblogs.com/zhilili/p/14764850.html