JavaScript 内存泄漏检测
Mehvish Ashiq
2024年2月15日
-
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()
中提供参考,并在不再需要它们时直接调用删除该函数。
作者: Mehvish Ashiq