詳細解釋 JavaScript 中的記憶體洩漏?
JavaScript 記憶體洩漏
JavaScript 是一種垃圾收集語言,這意味著當宣告變數時,它會自動為它們分配記憶體。當沒有更多對已宣告變數的引用時,分配的記憶體將被釋放。記憶體洩漏或大多數與記憶體相關的問題都發生在釋放記憶體期間。
一些常見的 JavaScript 記憶體洩漏
1) 意外的全域性變數
當引用未宣告的變數時,javascript 會在全域性物件中建立一個新變數。在下面的示例 1 中,假設語言的目的是僅引用 "myArray" 函式中的變數。如果我們不使用 var 宣告它,則會建立一個全域性變數。它可能不會造成太大危害,但主要問題在於意外地使用 "this" 關鍵字建立全域性變數,如示例 2 所示。
示例 1
function myArray(arg) { languages = "[javascript,.....]"; // created using window }
示例 2
function myArray(arg) { this.languages = "[javascript,.....]"; // global object }
由於全域性變數的作用域永不結束,因此即使不需要它們,它們也會在頁面執行期間一直保留在記憶體中。這種情況會導致垃圾收集器(在變數作用域結束時刪除動態記憶體)產生記憶體洩漏(記憶體中殘留未使用的物件)。全域性變數越多,記憶體洩漏就越多。
2) 閉包
閉包是一個內部函式,可以訪問外部函式的變數(作用域)。此外,即使外部函式已執行,內部函式仍將繼續訪問外部函式的作用域。當宣告的變數自動可用於內部巢狀函式並在記憶體中駐留,即使它在內部巢狀函式中沒有被引用時,也會發生記憶體洩漏。
在下面的示例中,由於閉包中的所有內部函式共享相同的上下文,innFun() 與 "function() {}" 共享相同的上下文,該上下文由外部函式返回。現在,每隔 3 毫秒,我們對 outFun 進行一次函式呼叫,一個新值(每次呼叫後)被分配給全域性變數 newvalue。只要一個引用指向此 "function() {}",就會保持共享作用域並保留陣列,因為它是內部函式 (innFun) 的一部分,即使內部函式從未被呼叫。每次呼叫外部函式 (outFun) 時,我們都會將前一個 function(){} 儲存到新函式的值(變數)中。因此,以前共享的作用域必須再次保留。因此,在外部函式 (outFun) 的第 n 次呼叫中,外部函式的第 (n-1) 次呼叫的陣列無法被垃圾回收。此過程最終會在記憶體耗盡時停止。
示例
var newvalue; function outFun() { var array = new Array(1000000); var value = newvalue; function innFun() { if (value) return array; } return function () {}; } setInterval(function () { newvalue = outFun(); }, 3);