目录
- 🔍 什么是内存泄漏(Memory Leak)?
- 🚨 常见的内存泄漏场景
- 1️⃣ 未清除的定时器(setInterval / setTimeout)
- 2️⃣ 全局变量(变量未正确释放)
- 3️⃣ 事件监听未清除
- 4️⃣ 闭包导致的内存泄漏
- 5️⃣ DOM 引用未释放
- 🛠 如何检测和防止内存泄漏?
- 1️⃣ 使用 Chrome DevTools 监测内存
- 2️⃣ 使用 `WeakMap` 和 `WeakSet`
- 3️⃣ 确保在 `useEffect` 里清理副作用(React)
- ✅ 总结
🔍 什么是内存泄漏(Memory Leak)?
内存泄漏 指的是 程序运行时,已经不再使用的内存无法被释放,导致内存占用不断增加,最终可能会导致应用性能下降甚至崩溃。
在 JavaScript 中,垃圾回收机制(GC, Garbage Collection) 会自动释放不再使用的变量,但某些情况下,对象仍然被错误地引用,导致 GC 无法回收,从而造成内存泄漏。
🚨 常见的内存泄漏场景
1️⃣ 未清除的定时器(setInterval / setTimeout)
当使用 setInterval
或 setTimeout
时,如果不手动清除,函数的引用会一直保留,导致内存泄漏。
function startTimer() {setInterval(() => {console.log("Running...");}, 1000);
}
// 调用后,即使不再需要,定时器仍然占用内存
startTimer();
✅ 解决方法:在组件销毁或不需要时清除定时器
const timer = setInterval(() => {console.log("Running...");
}, 1000);clearInterval(timer); // 及时清除定时器
2️⃣ 全局变量(变量未正确释放)
如果一个变量被赋值到 window
或全局作用域,它将一直存在,导致内存无法被回收。
window.leak = []; // 这个数组永远不会被回收
✅ 解决方法:避免在 window
作用域创建变量
(function() {let tempArray = [];
})();
3️⃣ 事件监听未清除
当事件监听器(如 addEventListener
)绑定到 DOM 元素上,但该元素被移除时,监听器仍然存在,导致 JavaScript 引用无法被释放。
document.getElementById("btn").addEventListener("click", function() {console.log("Clicked!");
});
✅ 解决方法:组件卸载时移除监听
const btn = document.getElementById("btn");
const handleClick = () => console.log("Clicked!");
btn.addEventListener("click", handleClick);// 在适当时机移除监听器
btn.removeEventListener("click", handleClick);
4️⃣ 闭包导致的内存泄漏
闭包 使得内部函数可以访问外部函数的变量,但如果变量一直被引用,GC 无法释放它。
function createClosure() {let data = new Array(1000000); // 大量数据return function () {console.log(data.length);};
}const closure = createClosure();
// `data` 变量不会被释放
✅ 解决方法:在不需要时手动清空变量
let closure = createClosure();
closure = null; // 解除引用,让 GC 回收
5️⃣ DOM 引用未释放
如果 JavaScript 变量仍然引用一个已删除的 DOM 元素,该元素不会被回收。
let div = document.getElementById("myDiv");
document.body.removeChild(div); // 移除 DOM
// 但 div 变量仍然持有该元素的引用,导致泄漏
✅ 解决方法:手动释放引用
div = null; // 解除 JavaScript 引用,让 GC 处理
🛠 如何检测和防止内存泄漏?
1️⃣ 使用 Chrome DevTools 监测内存
- 打开
Performance
面板 → 录制 → 检查内存占用 - 在
Memory
面板 中使用 Heap Snapshot,查看哪些对象未被释放。
2️⃣ 使用 WeakMap
和 WeakSet
WeakMap
和WeakSet
不会阻止垃圾回收,适用于临时数据存储。
let weakMap = new WeakMap();
let obj = { key: "value" };
weakMap.set(obj, "some data");
obj = null; // `obj` 被回收,WeakMap 也自动释放它的引用
3️⃣ 确保在 useEffect
里清理副作用(React)
如果在 React 组件中添加 事件监听、定时器 等,一定要在 useEffect
里清理:
useEffect(() => {const interval = setInterval(() => {console.log("Running...");}, 1000);return () => clearInterval(interval); // 组件卸载时清除定时器
}, []);
✅ 总结
- 内存泄漏 = 无用的对象无法被 GC 释放,导致内存占用持续增长。
- 常见原因:未清理 定时器、事件监听、闭包、DOM 引用、全局变量。
- 如何避免?
- 清除定时器和事件监听 (
clearInterval, removeEventListener
) - 避免不必要的全局变量
- 正确管理闭包(在不需要时清空变量)
- 使用 Chrome DevTools 检查内存泄漏
- 在 React 组件中使用
useEffect
清理副作用
- 清除定时器和事件监听 (