您好,登錄后才能下訂單哦!
本文實例講述了JS造成內存泄漏的幾種情況。分享給大家供大家參考,具體如下:
介紹:
js中的內存垃圾回收機制:垃圾回收器會定期掃描內存,當某個內存中的值被引用為零時就會將其回收。當前變量已經使用完畢但依然被引用,導致垃圾回收器無法回收這就造成了內存泄漏。傳統頁面每次跳轉都會釋放內存,所以并不是特別明顯。
Vue單頁面應用中:Web App 與 傳統Web的區別,因為Web App是單頁面應用頁面通過路由跳轉不會刷新頁面,導致內存泄漏不斷堆積,導致頁面卡頓。
泄漏點:
1.DOM/BOM 對象泄漏
2.script 中存在對DOM/BOM 對象的引用導致
3.Javascript 對象泄漏
4.通常由閉包導致,比如事件處理回調,導致DOM對象和腳本中對象雙向引用,這個時常見的泄漏原因
代碼關注點:
1.DOM中的addEventLisner 函數及派生的事件監聽, 比如Jquery 中的on 函數, vue 組件實例的 $on 函數,第三方庫中的初始化函數
2.其它BOM對象的事件監聽, 比如websocket 實例的on 函數
3.避免不必要的函數引用
4.如果使用render 函數,避免在html標簽中綁定DOM/BOM 事件
Vue如何處理:
1.如果在mounted/created 鉤子中綁定了DOM/BOM 對象中的事件,需要在beforeDestroy 中做對應解綁處理
2.如果在mounted/created 鉤子中使用了第三方庫初始化,需要在beforeDestroy 中做對應銷毀處理
3.如果組件中使用了定時器,需要在beforeDestroy 中做對應銷毀處理
4.模板中不要使用表達式來綁定到特定的處理函數,這個邏輯應該放在處理函數中?
5.如果在mounted/created 鉤子中使用了$on,需要在beforeDestroy 中做對應解綁($off)處理
6.某些組件在模板中使用 事件綁定可能會出現泄漏,使用$on 替換模板中的綁定
Vue官網講解避免內存泄露https://cn.vuejs.org/v2/cookbook/avoiding-memory-leaks.html
另外,vue 在IE edge瀏覽器下,父子組件的場景,子組件依賴父組件的狀態,子組件控制父組件狀態變化從而反饋給子組件的展示變化,子組件通過v-if模式存在于視圖中,父組件通過狀態控制子組件的v-if狀態變換。子組件控制父組件狀態完成子組件數據填充后,父組件切換子組件的v-if狀態,子組件占用dom結構被清理。此時,子組件存在時的內存占用未被釋放,當父組件再次回切v-if狀態時,子組件重新展示,內存飆升,重復幾次切換后,內存飆升明顯,頁面卡頓。
1.閉包
function fn1(){ var n=1; } //我想取到里面的局部變量n function fn1(){ var n=1; function fn2(){//在加一個fn2當他的子集 alert(n); } }
但是我在外面還是訪問不到那就return出來
function fn1(){ var n=1; function fn2(){//在加一個fn2當他的子集 alert(n); } return fn2(); //return出來后 他就給 window了所以一直存在內存中。因為一直在內存中,在IE里容易造成內存泄漏 } fn1();
盡量書寫的時候,避免這種情況。
2.意外的全局變量
一個未聲明變量的引用會在全局對象中創建一個新的變量。在瀏覽器的環境下,全局對象就是 window,也就是說:
function foo(arg) { bar = "aaaaa"; } 實際上等價于 function foo(arg) { window.bar = "aaaaa"; }
function foo() { this.variable = "qqqqq"; } //this 指向全局對象(window) foo();
為了防止這種錯誤的發生,可以在你的 JavaScript 文件開頭添加 'use strict';
語句
3.定時器setTimeout setInterval
當不需要setInterval或者setTimeout時,定時器沒有被clear,定時器的回調函數以及內部依賴的變量都不能被回收,造成內存泄漏。比如:vue使用了定時器,需要在beforeDestroy 中做對應銷毀處理。js也是一樣的。
clearTimeout(***) clearInterval(***)
4.如果在mounted/created 鉤子中使用了$on,需要在beforeDestroy 中做對應解綁($off)處理
beforeDestroy() { this.bus.$off('****'); }
5、給DOM對象添加的屬性是一個對象的引用
var testObject = {}; document.getElementById('idname').property = testObject; //如果DOM不被消除,則testObject會一直存在,造成內存泄漏
解決方法:
在window.onunload事件中寫上:
window.onunload=function(){ document.getElementById('idname').property = null; //釋放內存 };
6.DOM對象與JS對象相互引用
function testObject(element) { this.elementReference = element; // 為testObject(js)對象的屬性綁定element(DOM)對象 element.property = this; // 為element(DOM)對象的屬性綁定testObject(js)對象 } new testObject(document.getElementById('idname'));
解決方法:
在window.onunload事件中寫上:
document.getElementById('idname').property = null;
7.從外到內執行appendChild。這時即使調用removeChild也無法釋放
var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); document.body.appendChild(parentDiv); parentDiv.appendChild(childDiv);
解決方法:
從內到外執行appendChild:
var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); parentDiv.appendChild(childDiv); document.body.appendChild(parentDiv);
8.反復重寫同一個屬性會造成內存大量占用(但關閉IE后內存會被釋放)
for(i = 0; i < 5000; i++) { hostElement.text = "asdfasdfasdf"; }
這種方式相當于定義了5000個屬性!
9.注意程序邏輯,避免“死循環”之類的
10.echarts配合循環計時器等出現的內存泄漏
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具:http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。
更多關于JavaScript相關內容可查看本站專題:《JavaScript操作DOM技巧總結》、《JavaScript頁面元素操作技巧總結》、《JavaScript事件相關操作與技巧大全》、《JavaScript查找算法技巧總結》、《JavaScript數據結構與算法技巧總結》、《JavaScript遍歷算法與技巧總結》及《JavaScript錯誤與調試技巧總結》
希望本文所述對大家JavaScript程序設計有所幫助。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。