Skip to content

Go垃圾收集器详解 - Golang GC机制深度剖析

Go的垃圾收集器是并发三色标记清除算法的实现。深入理解GC机制对于性能调优至关重要。

📋 GC核心原理

go
package main

import (
    "fmt"
    "runtime"
    "runtime/debug"
    "time"
)

func main() {
    fmt.Println("=== Go垃圾收集器详解 ===")
    
    fmt.Printf("\n--- GC基本原理 ---\n")
    fmt.Printf("1. 三色标记算法\n")
    fmt.Printf("   - 白色: 未扫描的对象(待回收)\n")
    fmt.Printf("   - 灰色: 已扫描但引用未扫描\n")
    fmt.Printf("   - 黑色: 已扫描且引用已扫描\n")
    
    fmt.Printf("\n2. 并发标记\n")
    fmt.Printf("   - 与用户程序并发执行\n")
    fmt.Printf("   - 使用写屏障保证正确性\n")
    fmt.Printf("   - 减少STW时间\n")
    
    // GC调优
    fmt.Printf("\n--- GC调优 ---\n")
    
    // 设置GC目标百分比
    oldGOGC := debug.SetGCPercent(100)
    fmt.Printf("GOGC设置: %d (默认100)\n", 100)
    
    // 手动触发GC
    fmt.Printf("\n手动触发GC...\n")
    before := time.Now()
    runtime.GC()
    gcTime := time.Since(before)
    fmt.Printf("GC耗时: %v\n", gcTime)
    
    // 监控GC
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    
    fmt.Printf("\nGC统计:\n")
    fmt.Printf("  GC次数: %d\n", m.NumGC)
    fmt.Printf("  强制GC次数: %d\n", m.NumForcedGC)
    fmt.Printf("  GC CPU占用: %.2f%%\n", m.GCCPUFraction*100)
    
    // 创建一些垃圾触发GC
    fmt.Printf("\n--- 创建垃圾触发GC ---\n")
    
    for i := 0; i < 5; i++ {
        // 分配大量临时内存
        _ = make([]byte, 10*1024*1024) // 10MB
        
        var m2 runtime.MemStats
        runtime.ReadMemStats(&m2)
        fmt.Printf("迭代 %d: 堆大小 %.2f MB, GC次数 %d\n", 
            i+1, float64(m2.HeapAlloc)/1024/1024, m2.NumGC)
        
        time.Sleep(100 * time.Millisecond)
    }
    
    // 恢复原始GOGC
    debug.SetGCPercent(oldGOGC)
    
    fmt.Printf("\n🎯 GC优化建议:\n")
    fmt.Printf("1. 减少对象分配频率\n")
    fmt.Printf("2. 复用对象使用sync.Pool\n")
    fmt.Printf("3. 适当调整GOGC值\n")
    fmt.Printf("4. 避免大量小对象分配\n")
    fmt.Printf("5. 预分配slice/map容量\n")
    fmt.Printf("6. 使用pprof分析内存分配\n")
}

🎯 GC优化策略

  1. GOGC调整: 根据内存和性能需求调整
  2. 对象池: 使用sync.Pool减少分配
  3. 预分配: 为slice和map预分配容量
  4. 避免逃逸: 减少堆分配
  5. 批量处理: 减少GC触发频率

正在精进