Go中变量的生命周期

变量的生命周期

生命周期指变量在程序执行过程中存在的时间段。包级别变量的生命周期是整个程序的执行时间。相反,局部变量有一个动态的生命周期:每次执行声明语句时创建一个新的实体,变量一直生存到它变得不可访问,此时它占用的存储空间被回收。函数的参数和返回值也是局部变量,它们在其闭包函数被调用的时候创建。

for t := 0.0; t < cycles*2*math.Pi; t += res {
    x := math.Sin(t)
    y := math.Sin(t*freq + phase)
    img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
}

在如上代码片段中,变量t在每次for循环的开始创建,变量xy在循环的每次迭代中创建。

那么垃圾回收器如何知道一个变量是否应该被回收?基本思路是每个包级别的变量,以及每一个当前执行函数的局部变量,可以作为追溯该变量的路径的源头,通过指针和其他方式的引用可以找到变量。如果变量的路径不存在,那么变量变得不可访问,因此它不会影响任何其他的计算过程。

因为变量的生命周期是通过它是否可达来确定的,所以局部变量可在包含它的循环的一次迭代之外继续存活。即使包含它的循环已经返回,它的存在还可能延续。

编译器可以选择使用堆或栈上的空间来分配,且这个选择不是基于使用varnew关键字来声明变量:

var global *int
func f() {
    var x int
    x = 1
    global = &x
}

func g() {
    y := new(int)
    *y = 1
}

这里,x一定使用堆空间,因为它在f函数返回以后还可以从变量global访问,尽管它被声明为一个局部变量。这种情况我们说xf逃逸。相反,当g函数返回时,变量*y变得不可访问,可回收。因此*y没有从g中逃逸,所以编译器可以安全地在栈上分配*y,即便使用new函数来创建它。

任何情况下,逃逸的概念使开发者不需要额外费心来写正确的代码,但要记住它在性能优化的时候是有好处的,因为每一次变量逃逸都需要一次额外的内存分配过程。

垃圾回收对于写出正确的程序有巨大的帮助,但是免不了考虑内存的负担。不需要显式分配和释放内存,但是变量的生命周期是写出高效程序所必需清楚的。例如,在长生命周期对象中保持短生命周期对象不必要的指针,特别是在全局变量中,会阻止垃圾回收器回收短生命周期的对象空间。

参考资料

  • 《Go程序设计语言》

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值