内存泄漏可快速确认:先用任务管理器观察静置与重复操作后内存是否持续上涨;再用Performance面板录制并勾选Memory,若JS Heap呈阶梯式上升且GC后回落极小,则存在泄漏。

直接看内存曲线和操作反馈,比等用户投诉快得多。页面越用越卡、滚动变涩、输入延迟、偶尔崩溃,这些不是“体验问题”,而是内存正在被悄悄吃掉的明确信号。
三步快速确认是否真有泄漏
不用打开 DevTools 堆快照,先做这三件事:
- 按 Shift + Esc 打开浏览器任务管理器,盯住目标标签页的“内存”数值:静置 10 秒不操作,内存应基本持平;反复打开关闭同一个弹窗 5 次,每次操作后内存若都比前一次高 20MB 以上,大概率已泄漏
- 在 Performance 面板录制 15 秒操作(含滚动、点击、切换),勾选 Memory 选项;停止后查看“JS Heap”曲线——如果出现阶梯式上升、且每次 GC 后回落幅度极小(
- 执行同一操作前后各运行一次
performance.memory(Chrome 中支持),对比usedJSHeapSize:增长超过初始值 30%,且多次重复后持续放大,就是泄漏在积累
重点查这四类“内存钉子户”
80% 的泄漏来自固定模式,按优先级排查:
-
未清理的事件监听器:尤其 scroll、resize、input 这类高频事件;执行
getEventListeners(document)查全局监听,切换路由后再查,新增未清除的就是嫌疑对象 -
没清空的定时器:
setInterval或setTimeout回调里用了this、props、大型数组或 DOM 节点,却没在组件卸载时clearInterval(id) -
DOM 删除后 JS 还握着引用:比如
const node = document.getElementById('chart'); node.remove();,但node变量仍活着,整个 DOM 树片段就锁死在内存里 -
闭包偷偷留住大对象:函数返回了一个长期存活的回调,而这个回调又捕获了
new Array(1e6)或接口返回的原始数据,只要回调没被释放,数据就一直占着
用堆快照精准定位泄漏源
确认泄漏存在后,进 Memory 面板拍三张快照:
立即学习“Java免费学习笔记(深入)”;
- 刷新页面 → 拍第一张(基线)
- 执行疑似泄漏操作(如连续打开/关闭 3 个详情页)→ 拍第二张
- 再执行一次同样操作 → 拍第三张
- 选中第二、三张快照,切到 Comparison 视图,重点关注
Closure、Detached HTMLDivElement、Array这几类数量是否只增不减 - 点开异常增长的条目,看右侧
Retaining Path:路径顶端那个带@符号的对象,就是强引用源头,通常就是泄漏代码所在位置
让内存波动回归健康区间
修复不是追求“零增长”,而是让内存随操作起伏、并在空闲时回落:
- 所有
addEventListener必须配对removeEventListener;推荐用{ signal: abortController.signal }方式绑定,销毁时统一abortController.abort() - 组件生命周期结束时,显式清空定时器、取消未完成的 Promise、将大缓存对象设为
null(确保无其他引用) - 避免把 DOM 节点直接挂到全局或长期存活对象上;改用
WeakMap存储关联元数据 - 导出函数前检查是否无意捕获了大对象;必要时拆分逻辑,让闭包只保留真正需要的最小数据


















