转义分析显示通道为泄漏参数

obj*_*ect 6 go

我正在尝试做的事情: 我试图通过三个阶段来理解/构建go管道。阶段1向通道A写入。阶段2具有多个go例程。每个go例程都从通道A读取,执行一些操作并将结果写入通道Bn(通道B1,B2..Bn)。第3阶段创建了n(=第2阶段中的通道总数)go例程,每个go例程从第2阶段的一个Channel中读取。它基于https://blog.golang.org/pipelines中描述的有限并行性

问题: 管道按预期工作正常,操作在go例程之间分配。但是,当我进行转义分析时,发现从一个阶段发送到另一个阶段的通道参数被报告为“泄漏参数”。

代码段: 为简单起见,我发布的代码显示第1阶段通道的创建,第2阶段则打印从第1阶段读取的值。

package main

import "fmt"

func createStageOne(numOfJobs int) <-chan int {
   stageOneChannel := make(chan int)
   go func(nJobs int) {
      for i := 0; i < nJobs; i++ {
        stageOneChannel <- i
      }
      close(stageOneChannel)
   }(numOfJobs)
   return stageOneChannel
} // stageOneChannel closes and go routine exits once nJobs are completed 

func createStageTwo(in <-chan int, completionFlag chan struct{}) {
    go func() {
        for n := range in {
            fmt.Println("Received from stage 1 channel ", n)
        }
        completionFlag <- struct{}{}
    }()
}// Comes out of for loop when stage 1 channel closes and go routine also exits


func main() {
    numOfJobs := 10
    stageOneChannel := createStageOne(numOfJobs)

    done := make(chan struct{})
    createStageTwo(stageOneChannel, done)

    <-done
}
Run Code Online (Sandbox Code Playgroud)

这是逃生分析结果

$ go build -gcflags "-m -l"
# concurrentHTTP/stackoverflow
./pipeline.go:7:5: func literal escapes to heap
./pipeline.go:7:5: func literal escapes to heap
./pipeline.go:6:25: make(chan int) escapes to heap
./pipeline.go:17:5: func literal escapes to heap
./pipeline.go:17:5: func literal escapes to heap
./pipeline.go:16:21: leaking param: in
./pipeline.go:16:36: leaking param: completionFlag
./pipeline.go:19:16: "Received from stage 1 channel " escapes to heap
./pipeline.go:19:16: n escapes to heap
./pipeline.go:19:15: createStageTwo.func1 ... argument does not escape
./pipeline.go:29:14: make(chan struct {}) escapes to heap
Run Code Online (Sandbox Code Playgroud)

为什么逸出分析报告incompletedFlag标志中的泄漏参数?

And*_*ips 5

所讨论的参数是作为参考类型的通道。它们捕获在createStageTwo()中创建的闭包中,并且可以在createStageTwo()返回时继续在该闭包的go例程中使用。因此,它们被信号通知为泄漏参数。如果不是,那么它们将被放置在堆栈上,并且在main()完成它们时变为无效。

这并不意味着您有问题。逃逸分析无法检测到资源泄漏,大多数人永远都不需要使用它。(对于在GC堆上放置了意外的内容的性能问题,这可能很有用。)

(对不起,@ Volker我最初在评论中张贴了我的答案,这使您的问题无处解决。)