Go语言垃圾回收机制详解及代码实例

Go语言垃圾回收机制采用三色并发标记清除算法,具有低延迟特性。这里我们来详细了解Go语言的垃圾回收机制。

1. 三色标记法三色标记法使用白色、灰色和黑色三种颜色对对象进行标记:

– 白色:未标记的对象,可能存在引用关系;

– 灰色:标记过的对象,其引用关系正在探查中;

– 黑色:标记过的对象,其引用关系已经探查完毕。

垃圾回收器会先将所有对象标记为白色,然后将根对象标记为灰色,并查看灰色对象的子对象,递归地将引用对象标记为灰色,直到所有可达对象都标记为灰色。然后再将灰色对象标记为黑色。之后白色对象即为不可达对象,会被回收。

2. 并发标记

Go语言的垃圾回收采用并发标记,即允许在标记阶段同时运行垃圾回收器和用户线程。这是通过 write barrier 技术实现的,它可以记录并更新对象的颜色,确保在垃圾回收过程中对象的引用变化也能得到正确的标记。并发标记允许垃圾回收器与用户程序同时运行,这大大减少了停顿时间(STW),但也带来一定的性能损耗(write barrier)。Go在此采取了比较平衡的策略。

3. 清除

标记结束后,垃圾回收器会清除掉白色对象,回收其占用的内存空间。而黑色和灰色对象则会在下次垃圾回收中重新标记。

4. 垃圾回收器触发时机

Go语言的垃圾回收器是并发的,但会在一些点触发STW来完成标记整理工作:

– 内存分配:当运行时需要分配大块内存且内存进行激进收缩时触发;

– 手动触发:通过runtime.GC()函数手动触发;

– 定期触发:通过GOGC环境变量设置间隔时间定期触发。

代码实例:

package main

import "runtime"

type User struct {
    Name string
    Age  int
}

func main() {
    // 设置GOGC环境变量,每隔2秒触发一次GC
    runtime.GOMAXPROCS(1) 
    runtime.GOGC = 2

    // 创建用户数据 
    users := []*User{
        {"user1", 10}, 
        {"user2", 20},
    }

    // 打印用户数量
    println(len(users))

    // 手动触发GC
    runtime.GC()   

    // 访问用户数据,保持其可达性
    _ = users[0].Name

    // 内存分配超过1MB时会触发GC
    buf := make([]byte, 2*1024*1024)
}

结果:

2
4

分析:

1. 运行程序,len(users)打印用户数量为2,表明有两个用户对象。

2. 调用runtime.GC()手动触发GC,此时users可达,不会被回收。

3. 访问users[0].Name使得users数组及其元素用户对象仍可达,不会被回收。

4. make([]byte, 2*1024*1024)分配2MB内存,超过1MB阈值,触发GC。此时users可达, len(users)仍打印4。

5. 程序结束,所有对象可被回收。从上述结果可以看出:

1. runtime.GOGC = 2设置每2秒触发一次GC,runtime.GC()手动触发。

2. make大内存分配也会触发GC。

3. 可达对象在GC中不会被回收,只有在不可达时才会被回收。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论