【问题标题】:Why does this golang program create a memory leak?为什么这个 golang 程序会造成内存泄漏?
【发布时间】:2017-07-01 22:19:11
【问题描述】:

我正在尝试理解并发和 goroutine,并且对以下实验代码有几个问题:

  1. 为什么会造成内存泄漏?我认为 goroutine 结束时的 return 将允许与其关联的内存被清理。
  2. 为什么我的循环数几乎从未达到 999?事实上,当我输出到文件并研究输出时,我注意到它很少以两位数打印整数;它第一次打印“99”是第 2461 行,而“999”是第 6120 行。这种行为对我来说是出乎意料的,这显然意味着我并不真正了解 goroutine 调度发生了什么。

免责声明:

小心运行下面的代码,如果几秒钟后不停止它可能会导致系统崩溃!

代码

package main

import (
    "fmt"
    "sync"
)

func main() {
  var wg sync.WaitGroup
    for {
      // spawn four worker goroutines
      spawnWorkers(4, wg)
      // wait for the workers to finish
      wg.Wait()
    }
}

func spawnWorkers(max int, wg sync.WaitGroup) {
  for n := 0; n < max; n++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            f(n)
          return
        }()
    }   
}

func f(n int) {
    for i := 0; i < 1000; i++ {
      fmt.Println(n, ":", i)
    }
}

【问题讨论】:

  • 你在复制sync.WaitGroup;而是传递一个指向它的指针。
  • 运行 go vet 会显示错误。
  • 嗨@TimCooper,关于内存泄漏,你是对的!这确实解决了问题 #1,但在那种情况下,goroutine 4 运行得比其他的多得多;输出到 .txt 文件时,我可以看到 #1 第一次运行是第 1640001 行。这对我来说没有多大意义。
  • @dpog 你对n 的输出不是你所期望的。见:github.com/golang/go/wiki/…

标签: go memory-leaks concurrency


【解决方案1】:

感谢 Tim Cooper、JimB 和 Greg 提供帮助的 cmets。下面贴出修正后的代码供参考。

两个修复是通过引用传入 WaitGroup,修复了内存泄漏,以及将 n 正确传递到匿名 goroutine,以及

package main

import (
    "fmt"
    "sync"
)

func main() {
  var wg sync.WaitGroup
    for {
      // spawn four worker goroutines
      spawnWorkers(4,&wg)
      // wait for the workers to finish
      wg.Wait()
    }
}

func spawnWorkers(max int, wg *sync.WaitGroup) {
  for n := 0; n < max; n++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Done()
            f(n)
          return
        }(n)
    }   
}

func f(n int) {
    for i := 0; i < 1000; i++ {
      fmt.Println(n, ":", i)
    }
}

【讨论】:

    猜你喜欢
    • 2010-10-11
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2019-09-08
    • 2011-06-17
    • 2020-02-03
    • 1970-01-01
    • 2011-12-19
    相关资源
    最近更新 更多