JavaScript 記憶體洩漏檢測
-
JavaScript 中的
意外全域性變數
記憶體洩漏 -
使用
使用嚴格;
避免 JavaScript 中的記憶體洩漏 -
使用
"use strict";
來避免 JavaScript 中的全域性變數引起的記憶體洩漏 -
使用
{once: true}
和removeEventListener()
避免 JavaScript 中的 DOM 引用不足導致的記憶體洩漏 -
Forgotten Callbacks or Timer
引起的記憶體洩漏及其預防技術 -
在 JavaScript 中如何避免
被遺忘的回撥或計時器
不再需要記憶體洩漏的記憶體沒有返回到空閒記憶體池或作業系統。
在三種最常見的情況下可能會發生記憶體洩漏:意外全域性變數
、忘記的回撥或計時器
和 DOM 引用不足
。
JavaScript 中的 意外全域性變數
記憶體洩漏
意外全域性變數
未宣告為全域性
變數。垃圾收集器無法收集它們,從而導致記憶體洩漏。
name
變數被建立為全域性 window.name
,它分配的空間永遠不會被釋放。
function fn1() {
// `name` is not declared
name = new Array(99999999)
}
fn1();
使用使用嚴格;
避免 JavaScript 中的記憶體洩漏
function fn1() {
'use strict';
name = new Array(99999999)
}
fn1();
輸出:
未使用
變數未使用,需要刪除或正確處理以釋放記憶體空間。
最關鍵的一點是找到不再需要的記憶體。
JavaScript 使用垃圾收集器來確定程式碼的某個部分是否需要記憶體。
許多垃圾收集器使用 mark-and-sweep
演算法。
使用"use strict";
來避免 JavaScript 中的全域性變數引起的記憶體洩漏
在 Chrome DevTools 的 Memory
標籤頁上使用 heap allocations
。
你可以通過按 F12 或轉到 Right Click
-> Inspect
-> Memory
在 Chrome 中開啟 DevTools。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<button id="leak-button">Start</button>
<button id="stop-leak">Stop</button>
<script>
var x=[];
var running = false;
function grow(){
x.push(new Array(1000000).join('x'));
if(running)
setTimeout(grow,1000);
}
$('#leak-button').click(function(){
running = true;
grow();
});
$('#stop-button').click(function(){
running = false;
});
</script>
</body>
</html>
輸出:
在這裡,每當使用者單擊開始
按鈕並將包含百萬個 x
字元的字串推送到陣列中時,指令碼都會將 10.000
節點附加到 DOM
。
即使在按下停止
按鈕後,垂直的部分藍線也顯示記憶體洩漏。
變數 x
是記憶體洩漏的原因,因為它是一個全域性變數,即使不再需要它也會佔用空間。
使用 {once: true}
和 removeEventListener()
避免 JavaScript 中的 DOM 引用不足導致的記憶體洩漏
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<button id="trigger">Trigger</button>
<script>
var clickElement = document.getElementById("click");
const hugeString = new Array(100000).join('x');
clickElement.addEventListener("click", function(){
// hugeString is kept in the scope of callback forever
document.write(hugeString);
});
</script>
</body>
</html>
輸出:
活動的事件
偵聽器可以防止變數被垃圾收集。
使用 removeEventListener()
或將第三個引數作為 {once: true}
傳遞。
這樣,執行一次。listener
方法將被自動刪除。
Forgotten Callbacks or Timer
引起的記憶體洩漏及其預防技術
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
for (var i = 0; i < 100000; i++) {
var obj = {
call_again: function() {
var message = this;
var value = setTimeout(function() {
message.callAgain();
}, 100000);
}
}
obj.call_again();
obj = null;
}
</script>
</body>>
</html>
輸出:
timer callback
和它的繫結物件 obj
直到超時結束才被釋放。
timer
可以自行重置並永遠執行。因此,記憶體空間將始終保留,永遠不會空閒。
在 JavaScript 中如何避免被遺忘的回撥或計時器
通過在 setTimeout()
或 setInterval()
中提供參考,並在不再需要它們時直接呼叫刪除該函式。