visualizeGarbageCollection
可视化 V8 引擎的分代垃圾回收过程,展示新生代 Scavenge 算法和老生代 Mark-Sweep 算法的工作原理。
选择场景
GC 结果
总对象
5
存活
3
晋升
0
回收
2
释放内存
27 KB
新生代 GC (Scavenge)
步骤 1 / 12
初始化
初始化 新生代 GC:5 个年轻对象,0 个老对象
新生代 (1MB)
50 / 1024 KB
老生代 (4MB)
0 / 4096 KB
已释放
0 KB
新生代
From 空间
全局对象
5KB | 年龄:0
→ young1
新对象A
10KB | 年龄:0
→ young2
新对象B
8KB | 年龄:1
临时对象1
12KB | 年龄:0
临时对象2
15KB | 年龄:0
→ temp1
To 空间
老生代
V8 分代垃圾回收
V8 引擎使用分代垃圾回收策略,将对象分为新生代和老生代:
- 新生代 GC (Scavenge):
- 使用 From/To 两个空间(Semispace)
- 存活对象从 From 复制到 To 空间
- 交换 From/To 空间指针
- 速度快,适合短命对象
- 对象晋升:经历多次新生代 GC 后(通常2次),对象晋升到老生代
- 老生代 GC (Mark-Sweep):
- 标记阶段:从根开始遍历标记可达对象
- 清除阶段:回收未标记的对象
- 适合长命对象
- 循环引用:标记-清除算法能正确处理
函数签名
typescript
function visualizeGarbageCollection(
initialObjects: Array<{
id: string
name: string
references: string[]
isRoot: boolean
generation: 'young' | 'old'
age: number
size: number
}>,
gcType?: 'scavenge' | 'full'
): GCResult
interface GCResult {
/** 所有步骤 */
steps: GCStep[]
/** 最终存活的对象 */
survivors: string[]
/** 回收的对象 */
collected: string[]
/** 回收的内存 */
freedMemory: number
}
interface GCStep {
/** 步骤编号 */
stepNumber: number
/** GC 类型 */
gcType: 'scavenge' | 'mark-sweep' | 'full'
/** 操作类型 */
action: 'init' | 'scan' | 'copy' | 'swap' | 'promote' | 'mark' | 'sweep' | 'complete'
/** 当前处理的对象 ID */
currentObjectId?: string
/** 所有对象的状态 */
objects: GCObject[]
/** 说明 */
explanation: string
/** 已回收的对象 */
collected: string[]
/** 晋升的对象 */
promoted: string[]
/** 内存统计 */
memoryStats: {
youngTotal: number
youngUsed: number
oldTotal: number
oldUsed: number
freed: number
}
}
interface GCObject {
id: string
name: string
references: string[]
isRoot: boolean
size: number
age: number
generation: 'young' | 'old'
space?: 'from' | 'to'
marked: boolean
}参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
initialObjects | Array | 是 | 初始对象列表 |
gcType | 'scavenge' | 'full' | 否 | GC 类型,默认 'scavenge' |
对象属性
| 属性 | 类型 | 说明 |
|---|---|---|
id | string | 对象唯一标识 |
name | string | 对象名称 |
references | string[] | 引用的其他对象 ID |
isRoot | boolean | 是否为根对象 |
generation | 'young' | 'old' | 所在代 |
age | number | 对象年龄(经历的 GC 次数) |
size | number | 对象大小(KB) |
返回值
| 类型 | 说明 |
|---|---|
GCResult | 包含完整的 GC 执行步骤、存活对象、回收对象和内存统计 |
工作原理
V8 分代垃圾回收
V8 引擎将对象分为新生代和老生代,使用不同的 GC 算法:
1. 新生代 GC - Scavenge(复制算法)
新生代使用 Semispace 结构,分为 From 空间和 To 空间:
算法流程:
- 扫描:从根对象和老生代引用扫描新生代对象
- 复制:将存活对象从 From 复制到 To 空间
- 晋升:年龄达到阈值(通常2次)的对象晋升到老生代
- 清除:回收 From 空间中未复制的对象
- 交换:交换 From 和 To 空间指针
特点:
- 速度极快
- 空间利用率50%
- 适合生命周期短的对象
- 大部分对象很快死亡(婴儿假设)
2. 老生代 GC - Mark-Sweep + Mark-Compact
老生代使用标记-清除和标记-整理算法:
标记阶段:
- 从根对象开始深度优先遍历
- 标记所有可达对象
清除阶段:
- 遍历所有老对象
- 回收未标记的对象
整理阶段(可选):
- 移动存活对象,消除内存碎片
3. 对象晋升机制
新生代对象在以下情况晋升到老生代:
- 经历 N 次(通常2次)新生代 GC 仍存活
- To 空间使用率超过 25%
4. 循环引用处理
标记-清除算法天然支持循环引用:
对象A ⇄ 对象B (无根引用)即使 A 和 B 循环引用,只要从根无法访问,就会被回收。
使用示例
基础示例
typescript
// 新生代 GC
const result = visualizeGarbageCollection([
{ id: 'root', name: '全局对象', references: ['obj1'], isRoot: true, generation: 'young', age: 0, size: 5 },
{ id: 'obj1', name: '新对象', references: [], isRoot: false, generation: 'young', age: 1, size: 10 },
{ id: 'temp', name: '临时对象', references: [], isRoot: false, generation: 'young', age: 0, size: 15 }
], 'scavenge')
// result.survivors => ['root', 'obj1']
// result.collected => ['temp']
// result.freedMemory => 15对象晋升
typescript
const result = visualizeGarbageCollection([
{ id: 'root', name: 'Window', references: ['young'], isRoot: true, generation: 'old', age: 5, size: 10 },
{ id: 'young', name: '老对象', references: [], isRoot: false, generation: 'young', age: 2, size: 20 }
], 'scavenge')
// young 年龄达到 2,晋升到老生代
// result.promoted => ['young']完整 GC
typescript
const result = visualizeGarbageCollection([
{ id: 'root', name: 'Window', references: ['old1'], isRoot: true, generation: 'old', age: 10, size: 10 },
{ id: 'old1', name: '老对象', references: [], isRoot: false, generation: 'old', age: 8, size: 50 },
{ id: 'leak', name: '泄漏', references: [], isRoot: false, generation: 'old', age: 5, size: 100 }
], 'full')
// 先执行新生代 GC,再执行老生代 GC
// result.collected => ['leak']可视化功能
在 Playground 中,你可以:
选择预设场景
- 简单引用链
- 循环引用
- 复杂引用图
- 自定义场景
步进查看过程
- 使用控制器逐步查看 GC 执行
- 观察标记阶段如何从根开始遍历
- 观察清除阶段如何回收对象
可视化对象图
- 圆形节点代表对象
- 箭头代表引用关系
- 蓝色边框:根对象
- 绿色填充:已标记(可达)
- 黄色高亮:当前处理的对象
- 绿色箭头:可达对象间的引用
内存统计
- 总内存
- 使用中的内存
- 已释放的内存
实际应用
理解垃圾回收有助于:
- 避免内存泄漏:了解什么样的引用会导致对象无法回收
- 优化性能:减少不必要的对象创建和引用
- 理解闭包:闭包如何保持对外部变量的引用
- 调试问题:找出为什么某些对象没有被回收