【W(wǎng)eb技術(shù)】849- 前端常見(jiàn)內(nèi)存泄漏及解決方案

最近收到測(cè)試人員的反饋說(shuō)我們開(kāi)發(fā)的頁(yè)面偶現(xiàn)卡死,點(diǎn)擊無(wú)反應(yīng)的情況,特別是打開(kāi)頁(yè)面較久的時(shí)候發(fā)生概率較高。打開(kāi)任務(wù)管理器,看到內(nèi)存占有率已經(jīng)很高了,初步判斷可能存在內(nèi)存泄漏的情況。下面排查內(nèi)存泄漏的原因。
系統(tǒng)進(jìn)程不再用到的內(nèi)存,沒(méi)有及時(shí)釋放,就叫做內(nèi)存泄漏(memory leak)。當(dāng)內(nèi)存占用越來(lái)越高,輕則影響系統(tǒng)性能,重則導(dǎo)致進(jìn)程崩潰。Chrome 限制了瀏覽器所能使用的內(nèi)存極限(64 位為 1.4GB,32 位為 1.0GB)
引起內(nèi)存泄漏的原因
意外的全局變量
由于 js 對(duì)未聲明變量的處理方式是在全局對(duì)象上創(chuàng)建該變量的引用。如果在瀏覽器中,全局對(duì)象就是 window 對(duì)象。變量在窗口關(guān)閉或重新刷新頁(yè)面之前都不會(huì)被釋放,如果未聲明的變量緩存大量的數(shù)據(jù),就會(huì)導(dǎo)致內(nèi)存泄露。
未聲明變量
function?fn()?{
??a?=?'global?variable'
}
fn()
使用 this 創(chuàng)建的變量(this 的指向是 window)。
function?fn()?{
??this.a?=?'global?variable'
}
fn()
解決方法:
避免創(chuàng)建全局變量 使用嚴(yán)格模式,在 JavaScript 文件頭部或者函數(shù)的頂部加上 use strict。
閉包引起的內(nèi)存泄漏
原因:閉包可以讀取函數(shù)內(nèi)部的變量,然后讓這些變量始終保存在內(nèi)存中。如果在使用結(jié)束后沒(méi)有將局部變量清除,就可能導(dǎo)致內(nèi)存泄露。
function?fn?()?{
??var?a?=?"I'm?a";
??return?function?()?{
????console.log(a);
??};
}
解決:將事件處理函數(shù)定義在外部,解除閉包,或者在定義事件處理函數(shù)的外部函數(shù)中。
比如:在循環(huán)中的函數(shù)表達(dá)式,能復(fù)用最好放到循環(huán)外面。
//?bad
for?(var?k?=?0;?k?10;?k++)?{
??var?t?=?function?(a)?{
????//?創(chuàng)建了10次??函數(shù)對(duì)象。
????console.log(a)
??}
??t(k)
}
//?good
function?t(a)?{
??console.log(a)
}
for?(var?k?=?0;?k?10;?k++)?{
??t(k)
}
t?=?null
沒(méi)有清理的 DOM 元素引用
原因:雖然別的地方刪除了,但是對(duì)象中還存在對(duì) dom 的引用。
//?在對(duì)象中引用DOM
var?elements?=?{
??btn:?document.getElementById('btn'),
}
function?doSomeThing()?{
??elements.btn.click()
}
function?removeBtn()?{
??//?將body中的btn移除,?也就是移除?DOM樹(shù)中的btn
??document.body.removeChild(document.getElementById('button'))
??//?但是此時(shí)全局變量elements還是保留了對(duì)btn的引用,?btn還是存在于內(nèi)存中,不能被GC回收
}
解決方法:手動(dòng)刪除,elements.btn = null。
被遺忘的定時(shí)器或者回調(diào)
定時(shí)器中有 dom 的引用,即使 dom 刪除了,但是定時(shí)器還在,所以?xún)?nèi)存中還是有這個(gè) dom。
//?定時(shí)器
var?serverData?=?loadData()
setInterval(function?()?{
??var?renderer?=?document.getElementById('renderer')
??if?(renderer)?{
????renderer.innerHTML?=?JSON.stringify(serverData)
??}
},?5000)
//?觀察者模式
var?btn?=?document.getElementById('btn')
function?onClick(element)?{
??element.innerHTMl?=?"I'm?innerHTML"
}
btn.addEventListener('click',?onClick)
解決方法:
手動(dòng)刪除定時(shí)器和 dom。 removeEventListener 移除事件監(jiān)聽(tīng)
vue 中容易出現(xiàn)內(nèi)存泄露的幾種情況
在 Vue SPA 開(kāi)發(fā)應(yīng)用,那么就更要當(dāng)心內(nèi)存泄漏的問(wèn)題。因?yàn)樵?SPA 的設(shè)計(jì)中,用戶(hù)使用它時(shí)是不需要刷新瀏覽器的,所以 JavaScript 應(yīng)用需要自行清理組件來(lái)確保垃圾回收以預(yù)期的方式生效。因此開(kāi)發(fā)過(guò)程中,你需要時(shí)刻警惕內(nèi)存泄漏的問(wèn)題。
全局變量造成的內(nèi)存泄露
聲明的全局變量在切換頁(yè)面的時(shí)候沒(méi)有清空
<template>
??<div?id="home">這里是首頁(yè)div>
template>
建筑偷拍网
|
91免费在线视频
|
欧美孕妇一级片
|
国产熟妇XXXXXⅩ性Ⅹ交
|
国产特级乱浽片AA片
|
