垃圾回收机制(Garbage Collection)
JavaScript 自动内存管理机制。
📚 基本概念
什么是垃圾回收
垃圾回收(Garbage Collection,GC)是自动管理内存的机制,自动释放不再使用的对象占用的内存。
function createObject() {
const obj = { data: 'some data' };
return obj;
}
const myObj = createObject();
// 当 myObj 不再被引用时,对象会被垃圾回收🎯 垃圾回收算法
1. 标记清除(Mark and Sweep)
V8 引擎主要使用的算法:
- 标记阶段:从根对象开始,标记所有可达对象
- 清除阶段:清除未标记的对象
// 示例
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/WeakSet4. 使用对象池
// 重用对象,减少创建和销毁
class ObjectPool {
constructor(createFn) {
this.createFn = createFn;
this.pool = [];
}
acquire() {
return this.pool.pop() || this.createFn();
}
release(obj) {
this.pool.push(obj);
}
}🔧 调试工具
Chrome DevTools
- Memory 面板:查看内存使用
- Performance 面板:记录内存快照
- Heap Snapshot:分析堆内存
内存分析
// 检查内存使用
console.log(performance.memory);
// {
// usedJSHeapSize: 1000000,
// totalJSHeapSize: 2000000,
// jsHeapSizeLimit: 4000000
// }🔗 相关链接
参考: