JavaScript 垃圾回收与常见内存泄漏
JavaScript 垃圾回收与常见内存泄漏
JS 的内存分配和回收是自动的,但"自动"不代表不会泄漏。了解 GC 的工作方式,才能知道泄漏从哪来。
内存生命周期
const arr = [1, 2, 3] // 1. 分配内存
console.log(arr) // 2. 使用
// 3. 不再需要时,由 GC 自动回收
两种回收策略
引用计数(早期方案):记录每个对象被引用的次数,归零就回收。致命缺陷是循环引用——两个对象互相引用,计数永远不为零:
function fn() {
const a = {}
const b = {}
a.ref = b
b.ref = a
}
fn() // 函数结束后 a、b 都没用了,但引用计数法无法回收
标记清除(现代浏览器主流):GC 从根对象(window/global)出发,把能到达的对象全部标记,没标记到的就是"不可达",一律清除。循环引用只要从根出发不可达,照样回收。
V8 在标记清除基础上还做了分代优化:新生代用 Scavenge(复制算法,频繁小回收),老生代用标记清除+标记整理,减少全量扫描停顿。
四类典型内存泄漏
- 意外的全局变量
function fn() { x = new Array(100000) } // 漏写 const,挂到 window 上,永不释放
- 被遗忘的定时器 / 事件监听——回调里引用着外部数据,不 clear/remove 就一直活着
- 闭包持有——DOM 都删了,闭包还引用着关联数据
- 脱离 DOM 的引用——JS 变量缓存了 DOM 节点,节点删除后变量没置 null
const cache = {}
function add(id) { cache[id] = document.getElementById(id) }
add('box')
document.getElementById('box').remove() // DOM 没了,但 cache.box 仍引用,节点无法回收
如何排查
Chrome DevTools → Memory:拍堆快照(Heap snapshot),操作前后对比,看哪些对象只增不减;Performance Monitor 实时看 JS heap size 曲线,只涨不回落就有嫌疑。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~