0%

JavaScript 内存泄漏

什么是内存泄漏?

程序不再使用的内存没有释放。

常见原因

意外的全局变量

1
2
3
function func() {
leak = 'I am global' // 忘记 var/let
}

被遗忘的定时器

1
2
3
4
5
6
const interval = setInterval(() => {
// ...
}, 1000)

// 忘记清除
// clearInterval(interval)

闭包

1
2
3
4
5
6
7
function createLeak() {
const largeData = new Array(1000000)

return function() {
console.log(largeData.length)
}
}

DOM 引用

1
2
3
4
const element = document.getElementById('element')
const data = { element }

// 即使 DOM 移除,data.element 仍引用

检测工具

  • Chrome DevTools Memory 面板
  • heap snapshot

预防

  • 使用 let/const
  • 及时清除定时器
  • 移除事件监听器
  • 避免 DOM 引用

总结

内存泄漏是前端性能常见问题,主要由未释放引用导致。了解泄漏类型并使用工具检测是关键。

泄漏类型

  1. 意外的全局变量
    x = 1; 会创建全局变量,难以回收。

  2. 闭包保留
    回调函数持有外层变量,导致原本应该释放的对象继续存在。

  3. 被遗忘的定时器
    setIntervalsetTimeout 未清除。

  4. DOM 节点保留
    除 DOM 外的引用阻止其回收,如数组缓存引用到 DOM 元素。

  5. 循环引用
    普通对象之间循环引用不会直接导致泄漏,但在某些非标内存情况下会。

检测和诊断

  • Heap 快照:比较不同时间点的快照,找增长的对象。
  • Timeline/Performance:观察内存曲线。
  • Chrome DevTools 的 Allocation instrumentation:追踪内存分配。

避免策略

  • 使用 let/const,避免隐式全局
  • 定时器使用后 clearInterval / clearTimeout
  • 在组件销毁时解除事件监听 removeEventListener
  • 使用 WeakMap 保存 DOM 关联数据
  • 及时 null 化不再使用的变量

实战示例

1
2
3
4
5
function createLeak() {
const hugeArray = new Array(1000000).fill('*');
window.leak = hugeArray; // 全局引用造成泄漏
}
createLeak();

释放技巧

1
2
3
function clean() {
window.leak = null;
}

后端和 Node.js

在 Node 中也可能发生泄漏,常见于全局缓存、闭包和未关闭的流。

性能影响

泄漏会增加 GC 次数、拖慢响应并最终导致浏览器崩溃。定期监控对保持稳定运行至关重要。

工具推荐

  • MemLab(Facebook 的内存分析工具)
  • LeakCanary(移动端)
  • Chrome Treemap 可视化对象关系

进阶内容

  • 利用 WeakRef 和 FinalizationRegistry 管理弱引用
  • 使用 ESLint 插件 no-leaked-jquery-handlesno-closure-leak 检测潜在问题

结语

排查内存泄漏是开发中的重要环节,养成写干净代码的习惯并定期使用工具检查,可以大幅提升应用稳定性和性能。

内存泄漏影响性能。开发时注意,定期检查内存使用。内存泄漏补充 1
内存泄漏补充 2
内存泄漏补充 3
内存泄漏补充 4
内存泄漏补充 5
内存泄漏补充 6
内存泄漏补充 7
内存泄漏补充 8
内存泄漏补充 9
内存泄漏补充 10
内存泄漏补充 11
内存泄漏补充 12