JS 虽有垃圾回收(主流引擎基于可达性标记),但只要对象仍被意外持有引用就无法释放。前端常见泄漏场景:
- 闭包长期持有大对象或 DOM:回调引用了已不需要的变量,闭包不释放则变量常驻;
- 定时器未清理:
setInterval的回调持有外部引用,组件销毁后仍运行; - 事件监听未解绑:在
window/document上addEventListener后忘记removeEventListener,元素或组件无法回收; - 脱离 DOM 的引用:JS 变量仍引用已从文档移除的节点;
- 全局变量或全局缓存无限增长:如模块级 Map 只增不减;
- 第三方库实例未销毁:图表、编辑器等需调用
dispose/destroy。
排查手段:Chrome DevTools 的 Performance Monitor 观察 JS 堆趋势,用 Memory 面板拍堆快照(Heap Snapshot)对比,找 Detached DOM 和滞留对象。
预防习惯:SPA 中在组件卸载钩子里统一清理定时器、监听与订阅;大数据缓存用 WeakMap/WeakRef。追问:标记清除与引用计数的区别、GC 为什么回收不了循环引用外的可达对象。