JS造成內(nèi)存泄漏的幾種情況實(shí)例分析
本文實(shí)例講述了JS造成內(nèi)存泄漏的幾種情況。分享給大家供大家參考,具體如下:
介紹:
js中的內(nèi)存垃圾回收機(jī)制:垃圾回收器會(huì)定期掃描內(nèi)存,當(dāng)某個(gè)內(nèi)存中的值被引用為零時(shí)就會(huì)將其回收。當(dāng)前變量已經(jīng)使用完畢但依然被引用,導(dǎo)致垃圾回收器無(wú)法回收這就造成了內(nèi)存泄漏。傳統(tǒng)頁(yè)面每次跳轉(zhuǎn)都會(huì)釋放內(nèi)存,所以并不是特別明顯。
Vue單頁(yè)面應(yīng)用中:Web App 與 傳統(tǒng)Web的區(qū)別,因?yàn)閃eb App是單頁(yè)面應(yīng)用頁(yè)面通過(guò)路由跳轉(zhuǎn)不會(huì)刷新頁(yè)面,導(dǎo)致內(nèi)存泄漏不斷堆積,導(dǎo)致頁(yè)面卡頓。
泄漏點(diǎn):
1.DOM/BOM 對(duì)象泄漏
2.script 中存在對(duì)DOM/BOM 對(duì)象的引用導(dǎo)致
3.Javascript 對(duì)象泄漏
4.通常由閉包導(dǎo)致,比如事件處理回調(diào),導(dǎo)致DOM對(duì)象和腳本中對(duì)象雙向引用,這個(gè)時(shí)常見(jiàn)的泄漏原因
代碼關(guān)注點(diǎn):
1.DOM中的addEventLisner 函數(shù)及派生的事件監(jiān)聽(tīng), 比如Jquery 中的on 函數(shù), vue 組件實(shí)例的 $on 函數(shù),第三方庫(kù)中的初始化函數(shù)
2.其它BOM對(duì)象的事件監(jiān)聽(tīng), 比如websocket 實(shí)例的on 函數(shù)
3.避免不必要的函數(shù)引用
4.如果使用render 函數(shù),避免在html標(biāo)簽中綁定DOM/BOM 事件
Vue如何處理:
1.如果在mounted/created 鉤子中綁定了DOM/BOM 對(duì)象中的事件,需要在beforeDestroy 中做對(duì)應(yīng)解綁處理
2.如果在mounted/created 鉤子中使用了第三方庫(kù)初始化,需要在beforeDestroy 中做對(duì)應(yīng)銷(xiāo)毀處理
3.如果組件中使用了定時(shí)器,需要在beforeDestroy 中做對(duì)應(yīng)銷(xiāo)毀處理
4.模板中不要使用表達(dá)式來(lái)綁定到特定的處理函數(shù),這個(gè)邏輯應(yīng)該放在處理函數(shù)中?
5.如果在mounted/created 鉤子中使用了$on,需要在beforeDestroy 中做對(duì)應(yīng)解綁($off)處理
6.某些組件在模板中使用 事件綁定可能會(huì)出現(xiàn)泄漏,使用$on 替換模板中的綁定
Vue官網(wǎng)講解避免內(nèi)存泄露https://cn.vuejs.org/v2/cookbook/avoiding-memory-leaks.html
另外,vue 在IE edge瀏覽器下,父子組件的場(chǎng)景,子組件依賴父組件的狀態(tài),子組件控制父組件狀態(tài)變化從而反饋給子組件的展示變化,子組件通過(guò)v-if模式存在于視圖中,父組件通過(guò)狀態(tài)控制子組件的v-if狀態(tài)變換。子組件控制父組件狀態(tài)完成子組件數(shù)據(jù)填充后,父組件切換子組件的v-if狀態(tài),子組件占用dom結(jié)構(gòu)被清理。此時(shí),子組件存在時(shí)的內(nèi)存占用未被釋放,當(dāng)父組件再次回切v-if狀態(tài)時(shí),子組件重新展示,內(nèi)存飆升,重復(fù)幾次切換后,內(nèi)存飆升明顯,頁(yè)面卡頓。
js通常內(nèi)存泄漏的幾種情況的介紹
1.閉包
function fn1(){
var n=1;
}
//我想取到里面的局部變量n
function fn1(){
var n=1;
function fn2(){//在加一個(gè)fn2當(dāng)他的子集
alert(n);
}
}
但是我在外面還是訪問(wèn)不到那就return出來(lái)
function fn1(){
var n=1;
function fn2(){//在加一個(gè)fn2當(dāng)他的子集
alert(n);
}
return fn2();
//return出來(lái)后 他就給 window了所以一直存在內(nèi)存中。因?yàn)橐恢痹趦?nèi)存中,在IE里容易造成內(nèi)存泄漏
}
fn1();
盡量書(shū)寫(xiě)的時(shí)候,避免這種情況。
2.意外的全局變量
一個(gè)未聲明變量的引用會(huì)在全局對(duì)象中創(chuàng)建一個(gè)新的變量。在瀏覽器的環(huán)境下,全局對(duì)象就是 window,也就是說(shuō):
function foo(arg) {
bar = "aaaaa";
}
實(shí)際上等價(jià)于
function foo(arg) {
window.bar = "aaaaa";
}
function foo() {
this.variable = "qqqqq";
}
//this 指向全局對(duì)象(window)
foo();
為了防止這種錯(cuò)誤的發(fā)生,可以在你的 JavaScript 文件開(kāi)頭添加 'use strict'; 語(yǔ)句
3.定時(shí)器setTimeout setInterval
當(dāng)不需要setInterval或者setTimeout時(shí),定時(shí)器沒(méi)有被clear,定時(shí)器的回調(diào)函數(shù)以及內(nèi)部依賴的變量都不能被回收,造成內(nèi)存泄漏。比如:vue使用了定時(shí)器,需要在beforeDestroy 中做對(duì)應(yīng)銷(xiāo)毀處理。js也是一樣的。
clearTimeout(***) clearInterval(***)
4.如果在mounted/created 鉤子中使用了$on,需要在beforeDestroy 中做對(duì)應(yīng)解綁($off)處理
beforeDestroy() {
this.bus.$off('****');
}
5、給DOM對(duì)象添加的屬性是一個(gè)對(duì)象的引用
var testObject = {};
document.getElementById('idname').property = testObject; //如果DOM不被消除,則testObject會(huì)一直存在,造成內(nèi)存泄漏
解決方法:
在window.onunload事件中寫(xiě)上:
window.onunload=function(){
document.getElementById('idname').property = null; //釋放內(nèi)存
};
6.DOM對(duì)象與JS對(duì)象相互引用
function testObject(element) {
this.elementReference = element; // 為testObject(js)對(duì)象的屬性綁定element(DOM)對(duì)象
element.property = this; // 為element(DOM)對(duì)象的屬性綁定testObject(js)對(duì)象
}
new testObject(document.getElementById('idname'));
解決方法:
在window.onunload事件中寫(xiě)上:
document.getElementById('idname').property = null;
7.從外到內(nèi)執(zhí)行appendChild。這時(shí)即使調(diào)用removeChild也無(wú)法釋放
var parentDiv = document.createElement("div");
var childDiv = document.createElement("div");
document.body.appendChild(parentDiv);
parentDiv.appendChild(childDiv);
解決方法:
從內(nèi)到外執(zhí)行appendChild:
var parentDiv = document.createElement("div");
var childDiv = document.createElement("div");
parentDiv.appendChild(childDiv);
document.body.appendChild(parentDiv);
8.反復(fù)重寫(xiě)同一個(gè)屬性會(huì)造成內(nèi)存大量占用(但關(guān)閉IE后內(nèi)存會(huì)被釋放)
for(i = 0; i < 5000; i++) {
hostElement.text = "asdfasdfasdf";
}
這種方式相當(dāng)于定義了5000個(gè)屬性!
9.注意程序邏輯,避免“死循環(huán)”之類的
10.echarts配合循環(huán)計(jì)時(shí)器等出現(xiàn)的內(nèi)存泄漏
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具:http://tools.jb51.net/code/HtmlJsRun測(cè)試上述代碼運(yùn)行效果。
更多關(guān)于JavaScript相關(guān)內(nèi)容可查看本站專題:《JavaScript操作DOM技巧總結(jié)》、《JavaScript頁(yè)面元素操作技巧總結(jié)》、《JavaScript事件相關(guān)操作與技巧大全》、《JavaScript查找算法技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
相關(guān)文章
Javascript如何實(shí)現(xiàn)擴(kuò)充基本類型
這篇文章主要介紹了Javascript如何實(shí)現(xiàn)擴(kuò)充基本類型,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Javascript實(shí)現(xiàn)秒表計(jì)時(shí)游戲
這篇文章主要為大家詳細(xì)介紹了Javascript實(shí)現(xiàn)秒表計(jì)時(shí)游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
Javascript 實(shí)現(xiàn) Excel 導(dǎo)入生成圖表功能
這篇文章主要介紹了Javascript 實(shí)現(xiàn) Excel 導(dǎo)入生成圖表功能,本文通過(guò)實(shí)例代碼講解給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10
一個(gè)友好的.改善的 Object.prototype.toString的實(shí)現(xiàn)
一個(gè)友好的.改善的 Object.prototype.toString的實(shí)現(xiàn)...2007-04-04
在頁(yè)面中輸出當(dāng)前客戶端時(shí)間javascript實(shí)例代碼
這篇文章主要介紹了在頁(yè)面中輸出當(dāng)前客戶端時(shí)間javascript實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-03-03
JavaScript中數(shù)據(jù)結(jié)構(gòu)與算法(二):隊(duì)列
這篇文章主要介紹了JavaScript中數(shù)據(jù)結(jié)構(gòu)與算法(二):隊(duì)列,隊(duì)列是只允許在一端進(jìn)行插入操作,另一個(gè)進(jìn)行刪除操作的線性表,隊(duì)列是一種先進(jìn)先出(First-In-First-Out,F(xiàn)IFO)的數(shù)據(jù)結(jié)構(gòu),需要的朋友可以參考下2015-06-06
20個(gè)你不得不知道的JS async/await實(shí)用技巧
JavaScript的async和await關(guān)鍵詞是現(xiàn)代JavaScript異步編程的核心,它們讓異步代碼看起來(lái)和同步代碼幾乎一樣,使得異步編程變得更加直觀和易于管理,本文介紹20個(gè)關(guān)于async/await的實(shí)用技巧,將大大提升編程效率和代碼的清晰度,需要的朋友可以參考下2023-12-12

