17370845950

JavaScript垃圾回收算法
JavaScript垃圾回收通过自动管理内存防止泄漏。采用标记-清除解决引用计数的循环引用问题,V8引擎进一步使用分代回收与优化技术提升性能,开发者需注意意外全局变量、定时器等导致的内存泄漏。

JavaScript的垃圾回收(Garbage Collection, GC)是自动管理内存的机制,它负责释放不再使用的对象所占用的内存。开发者不需要手动释放内存,但理解其工作原理有助于避免内存泄漏和优化性能。

引用计数(Reference Counting)

这是早期的一种垃圾回收算法。每当一个对象被引用时,它的引用计数加1;当引用被解除时,计数减1。当计数为0时,对象就会被回收。

问题在于循环引用:如果两个对象互相引用,即使它们已经不再被程序使用,引用计数也不会为0,导致内存无法释放。

例如:

let objA = {};
let objB = {};
objA.ref = objB;
objB.ref = objA;

这两个对象在全局作用域中已无其他引用,但由于相互引用,引用计数不为0,无法被回收(在旧版本IE中曾引发问题)。

标记-清除(Mark-and-Sweep)

现代JavaScript引擎普遍采用这种算法。它从根对象(如全局对象、调用栈等)开始,遍历所有可达对象并“标记”它们。未被标记的对象被视为不可达,即不再使用,会被清除。

这个方法解决了引用计数的循环引用问题,因为即使对象间互相引用,只要它们无法从根访问,就会被回收。

主要步骤包括:

  • 从根开始遍历,标记所有可达对象
  • 扫描整个堆,清除未被标记的对象
  • 整理内存空间(可选)

现代引擎的优化策略

主流JavaScript引擎(如V8)使用更复杂的分代回收机制,基于“大多数对象生命周期很短”的观察。

V8将堆内存分为新生代和老生代:

  • 新生代(Young Generation):存放新创建的对象,使用Scavenge算法(如 Cheney 算法),快速复制存活对象到另一区域
  • 老生代(Old Generation):长期存活的对象会被晋升到老生代,使用标记-清除和标记-整理结合的方式回收

还引入了增量标记、并发标记和懒清理等技术,减少GC对主线程的阻塞,提升应用响应速度。

如何避免内存泄漏

虽然有自动回收机制,但不当编码仍会导致内存泄漏:

  • 意外的全局变量(如未声明的变量)
  • 未清理的定时器或事件监听器
  • 闭包中引用大量外部变量
  • DOM 引用未被释放(如移除的节点仍被JS持有)

建议定期检查内存使用情况,使用浏览器开发者工具分析堆快照和内存分配时间线。

基本上就这些。了解垃圾回收机制,能帮助写出更高效、稳定的JavaScript代码。不复杂但容易忽略。