示例:setInterval
或 setTimeout
未及时用 clearInterval
/clearTimeout
清除。
后果:定时器持续运行,其回调函数中引用的外部变量无法释放。
框架场景:在 React 的 useEffect
中启动定时器但未在清理函数中清除。
示例:给 DOM 元素添加事件监听(如 addEventListener
),但在元素销毁时未调用 removeEventListener
。
后果:被监听元素若被移除,但事件回调仍被持有,导致元素无法回收。
框架场景:Vue 组件的 beforeDestroy
生命周期中未移除事件监听。
示例:未使用 var
/let
/const
声明变量,或显式绑定到 window
(如 window.data = ...
)。
后果:全局变量始终可达,垃圾回收器不会回收。
注意:模块化开发可减少此类问题,但需警惕 this
的意外指向(如函数内非严格模式下的 this
指向 window
)。
示例:函数返回一个内部函数,且该函数被长期引用(如作为事件回调),导致外层函数的作用域链无法释放。
后果:闭包引用的外部变量会持续占用内存。
优化:在不再需要时手动解除引用(如将回调设为 null
)。
示例:JS 中保留了对已移除 DOM 元素的引用(如 const element = document.getElementById('x'); element.remove()
)。
后果:DOM 元素虽不在文档树中,但被 JS 变量引用,无法被回收。
解决:在移除 DOM 后,主动将变量设为 null
。
示例:使用 Map
或对象缓存数据,但未设置清理策略(如 LRU 算法)。
后果:缓存数据持续累积,占用内存。
优化:设置缓存上限或过期时间,定期清理无用数据。
示例:旧版 jQuery 插件可能在元素移除后保留引用;React 组件卸载后未取消网络请求或事件订阅。
后果:关联资源无法释放。
解决:遵循框架生命周期,在卸载时手动清理(如 React 的 useEffect
清理函数)。
示例:使用 Map
或 WeakMap
存储对象时,若用 Map
且未手动删除键,键对象无法释放。
区别:WeakMap
的键是弱引用,不会阻止垃圾回收。
检测工具:Chrome DevTools 的 Memory 面板(Heap Snapshots、Allocation Timeline)、Performance 面板监控内存趋势。
预防措施:
避免全局变量,使用严格模式('use strict'
)。
及时清除定时器、事件监听、异步回调。
在框架生命周期中清理资源(如 React 的 useEffect
返回清理函数)。
谨慎使用闭包,及时解除引用。
使用弱引用(WeakMap
/WeakSet
)替代强引用。
前端内存泄漏的核心是无用资源仍被引用,导致无法被垃圾回收。熟悉常见场景(如定时器、事件、闭包等),结合开发框架的生命周期管理,能有效避免此类问题。定期通过工具检测内存变化,是保障应用性能的关键。