垃圾回收机制

垃圾回收机制(GC)

核心思想

垃圾回收器会定期检查堆内存的对象,判断哪些对象仍然被引用(“可达”)或不再被引用(“不可达”)

对于不可达的对象,垃圾回收器会将其占用的内存进行回收

可达:该对象可以通过作用域链全局对象其他对象的引用来访问

回收算法

引用计数(已很少使用)

每个对象都有一个引用计数器,记录有多少引用指向它

当引用计数为 0 时,表示该对象不可达,可以被回收

但无法处理循环引用问题

1
2
3
4
5
6
7
8
9
function createCycle() {
let obj1 = {};
let obj2 = {};
obj1.ref = obj2; // obj1 引用 obj2
obj2.ref = obj1; // obj2 引用 obj1
return [obj1, obj2];
}
let cycle = createCycle();
cycle = null; // 即使外部没有引用,obj1 和 obj2 仍然互相引用
标记清除(最常用)

垃圾回收器从根对象(如全局对象)开始,递归地标记所有可达对象

标记完成后,未被标记的对象被视为不可达,其内存会被回收

1
2
3
let obj = { name: "Alice" };
obj = null; // obj 不再引用对象,对象变为不可达
// 垃圾回收器会在下一次运行时回收该对象的内存
分代回收(现代 V8 引擎常用优化策略)

将堆内存分为不同的区域(称为“代”),根据对象的生命周期进行管理:

  • 新生代(Young Generation):存储短期对象,垃圾回收频率较高。
  • 老生代(Old Generation):存储长期存活的对象,垃圾回收频率较低。

新生代中的对象如果经过多次垃圾回收后仍然存活,则会被晋升到老生代。

触发时机

内存不足时 || 周期性定时