【推薦課程:JavaScript教程】
內存泄漏
內存泄漏一般指的是當一個對象已經沒有作用了應該被回收時,另外一個正在使用的對象因對它的引用從而導致它不能被回收,這個不能被回收的對象停留在了堆內存中,這就造成了內存泄漏
當一個對象已經不需要再使用本該被回收時,另外一個正在使用的對象持有它的引用從而導致它不能被回收,這導致本該被回收的對象不能被回收而停留在堆內存中,這就產生了內存泄漏
常見的內存泄漏:
1、意外的全局變量
Js處理未定義變量的方式:未定義的變量會在全局對象創建一個新變量,在瀏覽器中,全局對象是window。
function foo(arg) { bar = "this is a hidden global variable"; //等同于window.bar="this is a hidden global variable" this.bar2= "potential accidental global";//這里的this 指向了全局對象(window), 等同于window.bar2="potential accidental global"}
解決方法:在JavaScript程序中添加,開啟嚴格模式'use strict',可以有效地避免上述問題。
注意:用來臨時存儲大量數據的全局變量,在確保處理完這些數據后要將其設置為null或者重新賦值。
2、DOM泄漏
在瀏覽器中DOM和JS所采用的引擎是不一樣的,DOM采用的是渲染引擎,而JS采用的是v8引擎,所以在用JS操作DOM時會比較耗費性能,所以為了減少DOM的操作,我們會采用變量引用的方式會將其緩存在當前環境。如果在進行一些刪除、更新操作之后,可能會忘記釋放已經緩存的DOM因此造成了內存泄漏
例:對沒有清理的DOM元素引用
var refA = document.getElementById('refA'); document.body.removeChild(refA); // #refA不能回收,因為存在變量refA對它的引用。 將其對#refA引用釋放,但還是無法回收#refA。
解決辦法:設置refA = null;
3、被遺忘的計時器和回調函數
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); } }, 1000);
這樣的代碼很常見, 如果id為Node的元素從DOM中移除, 該定時器仍會存在, 同時, 因為回調函數中包含對someResource的引用, 定時器外面的someResource也不會被釋放
4、循環引用
在js的內存管理環境中,如果對象 A 對B有訪問對象的權限,就稱為對象 A 引用對象 B。引用的計數的策略就是看對象有沒有其他對象引用到它,如果沒有對象引用這個對象,那么這個對象將會被回收 。
var obj1 = { a: 1 }; // 一個對象(稱之為 A)被創建,賦值給 obj1,A 的引用個數為 1 var obj2 = obj1; // A 的引用個數變為 2 obj1 = 0; // A 的引用個數變為 1 obj2 = 0; // A 的引用個數變為 0,此時對象 A 就可以被垃圾回收了
但是引用計數有個最大的問題就是循環引用。
function func() { var obj1 = {}; var obj2 = {}; obj1.a = obj2; // obj1 引用 obj2 obj2.a = obj1; // obj2 引用 obj1 }
當函數執行結束后,返回值為 undefined,所以整個函數以及內部的變量都應該被回收,但根據引用計數方法,obj1 和 obj2 的引用次數都不為 0,所以他們不會被回收。所以要解決這個問題可以設置它們的值為null
總結:
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com