常見的內存泄漏以及解決方案


一、什么是內存泄漏?

二、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)
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM