gpt4 book ai didi

go - 错误还是功能? Golang中 'range'和 'channel'相关的垃圾回收

转载 作者:IT王子 更新时间:2023-10-29 02:11:21 27 4
gpt4 key购买 nike

package main

import (
"sync"
"runtime"
)

type S struct {
chs chan int
}

var wg sync.WaitGroup

func worker(s *S) {
for i := range s.chs {
println("In worker, ch = ", i)
}

wg.Done()
}

func main() {
s := S{make(chan int)}

runtime.SetFinalizer(&s, func(ss *S) {
println("Finalizer")
close(ss.chs)
})


wg.Add(1)

go worker(&s)
for i := 0; i < 1; i++ {
s.chs <- 1
}

runtime.GC()

wg.Wait()
}

输出(转到 1.8.3):

In worker, ch = 1

Finalizer


我预计这个程序会死锁。 runtime.GC() 不会收集 s,因为 worker() 持有对 s.chs 的引用。

但是它以 go 1.8.3 终止。在s的finalizer中,连close(s.chs)都调用成功。

我想知道它是否与 range 和 GC 有什么特别的关系。

非常感谢。

最佳答案

我不是 100% 确定这是否是正在发生的事情,但是来自 runtime godoc,SetFinalizer 的倒数第二段| :

For example, if p points to a struct that contains a file descriptor d, and p has a finalizer that closes that file descriptor, and if the last use of p in a function is a call to syscall.Write(p.d, buf, size), then p may be unreachable as soon as the program enters syscall.Write. The finalizer may run at that moment, closing p.d, causing syscall.Write to fail because it is writing to a closed file descriptor (or, worse, to an entirely different file descriptor opened by a different goroutine). To avoid this problem, call runtime.KeepAlive(p) after the call to syscall.Write.

这对我来说意味着 Finalizer 最早可以在最后一次使用有问题的 var 之后立即运行。

我自己从未想过这种可能性,但从技术上讲,GC 能够在变量的作用域消失之前很久就知道它是否可以收集变量。考虑这个简单的例子。

func main() {
str := "Hello World"
fmt.Println(str)
someMainLoop()
// nothing after this, but someMainLoop() continues until stopped manually
}

str 没有理由不能被 GC 回收。它再也没有被使用过,而且它很可能知道这一点。

关于go - 错误还是功能? Golang中 'range'和 'channel'相关的垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46100756/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com