Skip to content

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
}

参数

参数名类型必填说明
initialObjectsArray初始对象列表
gcType'scavenge' | 'full'GC 类型,默认 'scavenge'

对象属性

属性类型说明
idstring对象唯一标识
namestring对象名称
referencesstring[]引用的其他对象 ID
isRootboolean是否为根对象
generation'young' | 'old'所在代
agenumber对象年龄(经历的 GC 次数)
sizenumber对象大小(KB)

返回值

类型说明
GCResult包含完整的 GC 执行步骤、存活对象、回收对象和内存统计

工作原理

V8 分代垃圾回收

V8 引擎将对象分为新生代老生代,使用不同的 GC 算法:

1. 新生代 GC - Scavenge(复制算法)

新生代使用 Semispace 结构,分为 From 空间和 To 空间:

算法流程

  1. 扫描:从根对象和老生代引用扫描新生代对象
  2. 复制:将存活对象从 From 复制到 To 空间
  3. 晋升:年龄达到阈值(通常2次)的对象晋升到老生代
  4. 清除:回收 From 空间中未复制的对象
  5. 交换:交换 From 和 To 空间指针

特点

  • 速度极快
  • 空间利用率50%
  • 适合生命周期短的对象
  • 大部分对象很快死亡(婴儿假设)

2. 老生代 GC - Mark-Sweep + Mark-Compact

老生代使用标记-清除标记-整理算法:

标记阶段

  1. 从根对象开始深度优先遍历
  2. 标记所有可达对象

清除阶段

  1. 遍历所有老对象
  2. 回收未标记的对象

整理阶段(可选):

  • 移动存活对象,消除内存碎片

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 中,你可以:

  1. 选择预设场景

    • 简单引用链
    • 循环引用
    • 复杂引用图
    • 自定义场景
  2. 步进查看过程

    • 使用控制器逐步查看 GC 执行
    • 观察标记阶段如何从根开始遍历
    • 观察清除阶段如何回收对象
  3. 可视化对象图

    • 圆形节点代表对象
    • 箭头代表引用关系
    • 蓝色边框:根对象
    • 绿色填充:已标记(可达)
    • 黄色高亮:当前处理的对象
    • 绿色箭头:可达对象间的引用
  4. 内存统计

    • 总内存
    • 使用中的内存
    • 已释放的内存

实际应用

理解垃圾回收有助于:

  • 避免内存泄漏:了解什么样的引用会导致对象无法回收
  • 优化性能:减少不必要的对象创建和引用
  • 理解闭包:闭包如何保持对外部变量的引用
  • 调试问题:找出为什么某些对象没有被回收