闭包会导致内存泄漏吗?如何避免?
闭包本身不是内存泄漏,它只是让变量的生命周期延长到与闭包一致。但如果闭包长期存在且不再需要引用的变量,就会造成实际的内存泄漏。
什么情况下闭包会导致内存泄漏
// 1. 意外引用:闭包引用了大对象但不使用
function createHandler() {
const hugeData = new Array(1000000).fill('*')
return function () {
console.log('handler') // 没用到 hugeData,但它被闭包引用了
}
}
const handler = createHandler() // hugeData 无法被回收
// 2. 定时器未清除
function startTimer() {
const data = getData()
setInterval(() => {
console.log(data) // data 一直被引用
}, 1000)
}
// 3. DOM 事件监听未移除
function bindEvent() {
const element = document.getElementById('btn')
const heavyData = { /* ... */ }
element.addEventListener('click', () => {
console.log(heavyData)
})
// 如果 element 被移除但监听器未移除 → 泄漏
}如何避免
- 及时清除引用:用完后将变量设为
null - 清除定时器:
clearInterval()/clearTimeout() - 移除事件监听:
removeEventListener() - 使用 WeakMap / WeakSet:不阻止 GC 回收
// WeakMap 解决方案
const cache = new WeakMap()
function process(obj) {
if (!cache.has(obj)) {
cache.set(obj, expensiveCompute(obj))
}
return cache.get(obj)
}
// 当 obj 被回收,cache 中的条目也会被自动清除现代浏览器
现代 V8 引擎已经能优化未使用的闭包变量,但在以下场景仍需注意:
- 长生命周期的 SPA 应用
- 频繁创建闭包的循环/递归
- 旧版浏览器(IE)的 DOM 循环引用