Go语言闭包持有环境范围与变量未被GC回收的疑问
Go闭包中指针指向变量未被回收的原因
问题描述
我参照线上闭包教程编写了如下代码:
func foo1() func() { xValue := 1 x := &xValue defer func() { xValue = 2 }() return func() { *x = *x + 1 fmt.Printf("foo1 val = %d\n", *x) } } func main() { f1 := foo1() f1() f1() f1() }
执行f1 := foo1()后,我认为变量xValue应该被回收,使用*x会出现错误,但代码运行正常,输出结果为:
foo1 val = 3 foo1 val = 4 foo1 val = 5
我想了解是闭包除指针本身外还持有指针指向的值,还是Go语言的垃圾回收机制导致xValue未被回收?
解答
这其实是Go的闭包捕获规则和垃圾回收机制共同作用的结果:
- 闭包会捕获它用到的所有变量,哪怕是通过指针间接引用的底层值。你代码里返回的匿名函数用到了指针
x,而x指向xValue,Go编译器能识别到xValue被闭包间接关联了,所以foo1执行完后不会立刻回收xValue的内存。 - 再捋一遍执行流程:调用
foo1时,先把xValue设为1,x指向它;然后defer的函数会在foo1返回前执行,把xValue改成2;最后返回的闭包攥着对x的引用,只要f1还在,x指向的xValue就会被GC判定为“还在被使用”,不会被回收。 - 每次调用
f1(),都会给*x(也就是xValue)加1,所以第一次调用是2+1=3,之后每次加1,就有了你看到的输出结果。
总结一下:闭包通过指针间接引用了xValue,Go的GC会跟踪这种引用关系,只要闭包还存在,xValue就会一直留在内存里,不会被回收。
内容的提问来源于stack exchange,提问作者Shuaike Jiang
相关产品推荐
相关产品推荐

