
引言
最近有一个工单是说用户在使用我们的系统的时候,如果使用某个页面的次数多了以后浏览器就开始变慢甚至卡死崩溃掉。这个问题明显是提示有内存泄露,今天就由这个问题开始分享一些关于内存泄漏的知识。
一、 Web 应用内存泄漏的危害与易忽略性
危害:
- 性能下降:内存泄漏导致浏览器内存占用持续增长,页面卡顿、响应延迟,最终可能崩溃
- 资源耗尽:移动设备电池消耗加剧,低端设备体验恶化
- 跨页面影响:SPA(单页应用)因无页面刷新,泄漏累积更严重
易忽略原因:
- 渐进性:泄漏初期症状不明显,用户仅感知轻微卡顿,难及时反馈
- 工具缺失:开发者缺乏实时监控手段,需主动使用 DevTools 分析
- 框架依赖:Vue/React 等框架的自动回收机制让开发者误以为无需手动管理
二、 什么是内存泄漏
- 核心概念:程序申请内存后未释放,导致无效内存占用持续增长
- JavaScript 中的表现:对象未被 GC 回收。即使不再使用,仍被全局变量、闭包或事件监听器引用
常见场景:
1. 意外的全局变量
// javascript function leak() { leakedVar = '全局泄漏'; // 未使用var/let/const,成为window属性 }
- 原因:未声明的变量会挂载到window对象,直到页面关闭才释放。
- 解决:严格模式(‘use strict’)或明确声明变量
2. 未清除的定时器与回调
// javascript const intervalId = setInterval(() => { // 重复操作 }, 1000); // 未调用 clearInterval(intervalId)
- 影响:定时器持续引用函数,阻止垃圾回收(GC)。
- 解决:在组件卸载或不再需要时清除定时器(clearInterval/clearTimeout)。
3. DOM引用未释放
// javascript const elements = { button: document.getElementById('myButton') }; document.body.removeChild(elements.button); // 移除了DOM节点 // 但 elements.button 仍保留引用
- 原因:JavaScript对象持有DOM引用,即使节点已从DOM树移除。
- 解决:移除节点后手动置空引用(elements.button = null)
4. 闭包引用
// javascript function createClosure() { const largeData = new Array(1000000).fill('data'); return () => console.log(largeData); // 闭包持有largeData } const closure = createClosure(); // largeData无法被GC回收
- 风险:闭包可能无意中持有大型数据结构。
- 解决:避免在闭包中保留不必要的数据,必要时手动解除引用。
5.未移除的事件监听器
// javascript document.addEventListener('click', handleClick); // 页面卸载时未调用 removeEventListener
- 后果:事件监听器阻止相关对象被回收。
- 解决:使用removeEventListener或在框架中利用生命周期钩子(如Angular的OnDestroy清理函数)
6. Web Workers未终止
// javascript const worker = new Worker('worker.js'); // 未调用 worker.terminate()
- 影响:Worker线程持续占用内存。

最低0.47元/天 解锁文章
742

被折叠的 条评论
为什么被折叠?



