系統進程不再用到的內存,沒有及時的釋放,就叫做內存泄漏。
由於js對沒有進行申明的變量會默認是在全局變量上定義的,而系統的全局變量是 window,只有關閉窗口和刷新頁面,全局變量才會被釋放,如果在一個沒有聲明的變量上保存了大量的數據,這些數據就會保存在全局變量上,當這些數據沒有及時的被回收,就會發生 內存泄漏。
- 沒有聲明的變量
function fn(){ a='hello' } fn();
- 使用this申明的變量
function fn(){ // 這里的this指向它的調用者,他的調用者是window this.a='hello'; } fn()
解決方法:
避免使用沒有聲明的變量;
使用 嚴格模式,在js文件頭部或者是函數首行使用嚴格模式
由於閉包可以訪問函數內部的變量,讓這些變量一直保存在內存中,如果沒有及時的清理掉這些變量,就會發生內存泄漏。
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
雖然在別的地方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
定時器中有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開發的SPA應用,更需要關注內存泄漏,因為VUE項目是不會刷新頁面的,所以 Vue 應用需要自行清理組件來確保垃圾回收以預期的方式生效。
全局變量在頁面切換的時候沒有被清空。
export default { mounted() { window.test = { // 此處在全局window對象中引用了本頁面的dom對象 name: home , node: document.getElementById( home ), } }, }
解決方法:在頁面卸載的時候就將全局變量被清空
特別注意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) }