内存泄漏

内存泄漏

不再使用的内存未被 GC 机制释放,导致 内存占用持续增长,最终可能引发性能问题或程序崩溃。

该问题只存在于启动的相关页面进程中,并不会永久性地占据电脑内存

一旦相关进程结束(关闭浏览器标签、重启浏览器或应用)操作系统会回收该进程占用的所有内存。

导致成因

全局变量

意外出现的全局变量

全局变量不会被 GC 回收,直到页面关闭

1
2
3
function leak() {
leakedData = new Array(1000000); // 未使用 var/let/const,变量变为全局变量
}
  • 使用严格模式('use strict')避免隐式全局变量
闭包

闭包引用的外部变量会长期驻留内存

1
2
3
4
5
function createClosure() {
const largeData = new Array(1000000);
return () => console.log(largeData); // largeData 被闭包引用,会长期驻留内存
}
const closure = createClosure();
  • 手动解除引用(如 closure = null
定时器&回调函数

定时器未清除时,回调函数及其引用变量无法释放

1
2
3
const timer = setInterval(() => {
// 长期运行的定时器,内部可能持有外部变量
}, 1000);
  • 使用 clearInterval(timer)clearTimeout 及时清理
未解绑的DOM事件监听

DOM 元素被移除后,事件监听器仍可能持有引用

1
2
3
const button = document.getElementById('button');
button.addEventListener('click', handleClick);
// 如果元素被移除但未解绑事件,handleClick 和关联的 DOM 元素可能泄漏
  • 移除元素前调用 removeEventListener
DOM引用残留

JS 对象持有 DOM 引用时,DOM 元素无法被 GC 回收

1
2
3
4
const elements = {
button: document.getElementById('button'),
};
// 即使从页面移除 button,elements.button 仍保留对 DOM 的引用
  • 手动解除引用(如 elements.button = null
缓存

未限制缓存大小,数据堆积导致内存占用上升

1
2
3
4
const cache = {};
function addToCache(key, data) {
cache[key] = data; // 缓存数据无限增长
}
  • 使用 LRU 缓存策略或定期清理

排查方法

使用Chrome浏览器 F12→Memory面板

选 Allocations on timeline

多次对比堆快照

image-20250419024200478