垃圾回收机制(Garbage Collection)

JavaScript 自动内存管理机制。


📚 基本概念

什么是垃圾回收

垃圾回收(Garbage Collection,GC)是自动管理内存的机制,自动释放不再使用的对象占用的内存。

function createObject() {
  const obj = { data: 'some data' };
  return obj;
}
 
const myObj = createObject();
// 当 myObj 不再被引用时,对象会被垃圾回收

🎯 垃圾回收算法

1. 标记清除(Mark and Sweep)

V8 引擎主要使用的算法:

  1. 标记阶段:从根对象开始,标记所有可达对象
  2. 清除阶段:清除未标记的对象
// 示例
let obj1 = { name: 'Alice' };
let obj2 = { name: 'Bob' };
obj1.friend = obj2;
obj2.friend = obj1;
 
obj1 = null;
obj2 = null;
// 两个对象形成循环引用,但标记清除算法可以处理

2. 引用计数(Reference Counting)

记录每个对象的引用次数,当引用数为 0 时回收:

// 问题:无法处理循环引用
let obj1 = {};
let obj2 = {};
obj1.ref = obj2;
obj2.ref = obj1;
// 引用计数无法回收(现代浏览器已不使用)

🔍 内存泄漏

常见原因

1. 全局变量

// ❌ 错误:创建全局变量
function createData() {
  data = new Array(1000000).fill(0); // 未使用 var/let/const
}
 
// ✅ 正确
function createData() {
  const data = new Array(1000000).fill(0);
  return data;
}

2. 闭包

// ⚠️ 注意:闭包可能持有大对象
function createHandler() {
  const largeData = new Array(1000000).fill(0);
  return function() {
    // largeData 被闭包持有,无法释放
    console.log('Handler');
  };
}

3. 事件监听器

// ❌ 错误:未移除事件监听器
element.addEventListener('click', handler);
 
// ✅ 正确:移除事件监听器
element.addEventListener('click', handler);
element.removeEventListener('click', handler);

4. 定时器

// ❌ 错误:未清除定时器
const timer = setInterval(() => {
  console.log('Running');
}, 1000);
 
// ✅ 正确:清除定时器
clearInterval(timer);

5. DOM 引用

// ⚠️ 注意:DOM 引用可能阻止垃圾回收
const elements = [];
for (let i = 0; i < 1000; i++) {
  const element = document.createElement('div');
  elements.push(element); // 持有 DOM 引用
  document.body.appendChild(element);
}
 
// 需要清理
elements.forEach(el => el.remove());
elements.length = 0;

💡 优化建议

1. 及时释放引用

function processData() {
  const data = fetchLargeData();
  // 处理数据
  process(data);
  // 及时释放
  data = null;
}

2. 使用 WeakMap/WeakSet

// WeakMap 的键是弱引用,不会阻止垃圾回收
const weakMap = new WeakMap();
const obj = { data: 'large data' };
weakMap.set(obj, 'value');
// 当 obj 不再被引用时,WeakMap 中的条目会被自动清除

3. 避免循环引用

// 如果可能,避免循环引用
// 或使用 WeakMap/WeakSet

4. 使用对象池

// 重用对象,减少创建和销毁
class ObjectPool {
  constructor(createFn) {
    this.createFn = createFn;
    this.pool = [];
  }
  
  acquire() {
    return this.pool.pop() || this.createFn();
  }
  
  release(obj) {
    this.pool.push(obj);
  }
}

🔧 调试工具

Chrome DevTools

  1. Memory 面板:查看内存使用
  2. Performance 面板:记录内存快照
  3. Heap Snapshot:分析堆内存

内存分析

// 检查内存使用
console.log(performance.memory);
// {
//   usedJSHeapSize: 1000000,
//   totalJSHeapSize: 2000000,
//   jsHeapSizeLimit: 4000000
// }

🔗 相关链接


参考


javascript 性能优化 垃圾回收 内存管理 gc