如果局部变量在放入通道后失去其作用域,会发生什么情况?

特别是当变量在本地作用域内生成时。它的存活时间有多长?


例如,给定一个循环创建 10 只狗,并将指针传递到一个通道中,例如


for i := 0; i < 10; i++ {

    dogAddr := produce(i)    // assume we already have: func produce(i int) *Dog 

    c <- dogAddr             // c: channel

}

当循环结束时,狗会立即被释放吗?它们会只存活一段神奇的时间等待被消耗,它们会在被消耗后被释放吗?


我在一个简单的代码中对此进行了测试,结果似乎表明局部变量将永远存在。


package main


import (

    "fmt"

    "time"

)

func main() {

    var a int

    var c chan *int = make(chan *int, 1000)

    var m map[int]*int = make(map[int]*int)

    for i := 0; i < 10; i++ {                     // this is generation-loop

        x := i

        m[i] = &x

        fmt.Println(i, "mapping to: ", &a)

        c <- &x

    }                                            // the generation-loop breaks here

    for i := 0; i < 10; i++ {

        fmt.Println(i, "stored pointer: ", m[i]) // we can still call the variables 

    }

    for i := 0; i < 10; i++ {

        fmt.Println(i, "stored value: ", *m[i])  // we can still call the variables 

        p := <-c

        fmt.Println(i, "channel value: ", *p)    // we can still call the variables 

    }

    time.Sleep(20 * time.Second)


}

我对为什么会发生这种情况感到非常困惑。只要局部块完成,局部变量就不会失去其寿命吗?如果我使用的方式是错误的,那么在Go中将局部变量传递给外部用户的正确方法是什么?


慕勒3428872
浏览 71回答 1
1回答

holdtom

围棋是垃圾收集。当不再有对资源的引用(包括当前保存在缓冲通道中的引用)时,将释放资源。您不必担心释放后使用,并且返回/发送指向“局部”变量的指针也没有错。只要局部块完成,局部变量就不会失去其寿命吗?不,当垃圾回收器没有发现对其价值的进一步引用时,它们会“失去生命”。超出其封闭作用域的变量会自动在堆上分配,并且在流从封闭作用域返回并且其堆栈内存丢失后可以安全使用。可以这样想:在 Go 中没有“局部”变量这样的东西,它比它的范围长。这是不可能的。根据定义,超出声明范围的变量不是该意义上的“本地”变量,它会自动移动到堆中,并且只要任何内容继续引用它,它就会存活。值得扩展的内容:for&nbsp;i&nbsp;:=&nbsp;0;&nbsp;i&nbsp;<&nbsp;10;&nbsp;i++&nbsp;{ &nbsp;&nbsp;&nbsp;dogAddr&nbsp;:=&nbsp;produce(i)&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;assume&nbsp;we&nbsp;already&nbsp;have:&nbsp;func&nbsp;produce(i&nbsp;int)&nbsp;*Dog&nbsp; &nbsp;&nbsp;&nbsp;c&nbsp;<-&nbsp;dogAddr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;c:&nbsp;channel}当循环结束时,狗会立即被释放吗?你的困惑似乎要么源于变量本身在某种程度上与它所指向的内存同义的想法,要么源于一个错误的想法,即指针超出范围会以某种方式导致它所指向的记忆被回收,而其他东西仍然指向它,这在任何语言中都不是真的, 垃圾回收与否。dogAddrdogAddr指针只包含一个地址。该变量在循环的每次迭代中都会超出范围,但它所保存的值(堆上对象的地址)已被值复制到通道中。是的,是一个“局部”变量,但这并不重要。它的值不是“本地的”,它的值是内部分配下来的某个非本地对象的内存地址。dogAddrDogdogAddrDogprocess()我在一个简单的代码中对此进行了测试,结果似乎表明局部变量将永远存在。不,您刚刚表明,只要您引用了一点内存,该内存就不会被垃圾回收。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go