JavaScript内存泄漏是本该释放的对象仍被引用导致GC无法回收,表现为页面卡顿、滚动变慢等;四类高频场景:意外全局变量、未清理定时器、未解绑事件监听器、Detached DOM节点引用。

JavaScript 内存泄漏不是报错,而是“悄悄吃掉内存”——页面不崩溃,但越来越卡、滚动变慢、切换标签页延迟,甚至被浏览器强制杀进程。它本质是:本该释放的对象仍被引用,导致垃圾回收器(GC)无法回收。识别关键看四类高频场景,每类都有典型写法和一眼可辨的痕迹。
意外创建的全局变量
非严格模式下漏写 let/const/var,或用 this 赋值,变量会自动挂到 window(浏览器)或 global(Node),整个页面生命周期都不会释放。
- 常见写法:
function foo() { data = new Array(1e6); }或function bar() { this.cache = bigImage; } - 识别线索:控制台输入
window.data或window.cache能取到值;ESLint 报no-implicit-globals警告 - 预防动作:所有文件顶部加
"use strict";编辑器开启严格模式检查;避免手动往window挂大对象
未清理的定时器和回调函数
setInterval/setTimeout 回调若长期存在,且内部引用了外部大对象(如数据、DOM、Canvas),这些对象就会被“锁住”,无法释放。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 常见写法:
const list = hugeData(); setInterval(() => console.log(list.length), 1000); - 识别线索:组件卸载后,定时器仍在运行;Chrome Memory 面板中 Closure 下大量重复实例,Retaining Path 显示指向 setInterval
- 预防动作:在组件销毁时显式调用
clearInterval(id)或clearTimeout(id);轮询任务改用requestIdleCallback或按需触发
未移除的事件监听器
给 DOM、window 或 document 绑定事件后,若元素被移除或组件卸载,却没配对调用 removeEventListener,监听函数及其闭包里的引用就持续驻留。
立即学习“Java免费学习笔记(深入)”;
- 常见写法:
btn.addEventListener('click', handler); btn.remove(); // 忘记解绑或 React 中useEffect里漏写清除函数 - 识别线索:打开/关闭弹窗多次后,EventListener 数量只增不减;快照中看到大量 HTMLButtonElement 或 window 引用 Detached 节点
- 预防动作:绑定时保存回调引用,卸载时明确解绑;优先使用
{ once: true }处理单次事件;复杂场景用 WeakMap 关联监听逻辑与 DOM
Detached DOM 树(脱离 DOM 的节点引用)
从 DOM 中移除了节点(如 el.remove() 或 parent.removeChild(el)),但 JS 代码仍持有对该节点的引用(存在数组、对象、缓存中),节点虽不可见,样式、事件、子树全占内存。
- 常见写法:
const cache = [document.getElementById('modal')]; modal.remove(); // cache 还存着它 - 识别线索:Memory 快照中出现大量 Detached HTMLDivElement 等;节点已无父级,却被 JS 对象强引用
- 预防动作:移除 DOM 前先清空所有 JS 引用;避免用普通对象/数组长期缓存 DOM 节点;必须关联时,用
WeakMap存储(键为节点,节点销毁后自动清理)

















