memory-leaks - Golang WaitGroup导致内存泄漏,我该怎么做才能改进这个功能

标签 memory-leaks go

我一直在努力寻找我们应用程序中的内存泄漏,并一直在使用 pprof 工具来了解发生了什么。

当我查看堆时,我不断看到以下函数,但我不明白为什么(或者如果)它实际上是一个问题。

func CreateClients(raw []byte) bool {

    macs := []string{}
    conn := FormatConn(raw)

    if conn.Ap_Mac != "" {

        var wg sync.WaitGroup
        var array []Client

        c1 := make(chan Client)

        clients := FormatClients(conn)

        wg.Add(len(clients))

        for _, c := range clients {
            go func(d Client) {
                defer wg.Done()
                c1 <- UpdateClients(d)
            }(c)
        }

        go func() {
            defer wg.Done()
            for {
                select {
                case client := <-c1:
                    array = append(array, client)
                    macs = append(macs, client.Client_Mac)
                }
            }
        }()

        wg.Wait()
        // Do some other stuff
    ...
}

UpdateClients 函数更新 Mongo 中的客户端模型。当它返回时,我需要每个客户端 - 所以我可以用 ES 对它进行索引,而且我需要一个 mac 数组来做一些其他的事情。

我浏览了在线示例,认为这是遍历 channel 的推荐方式。

我的 pprof 堆看起来像这样,并且在几天内稳定增长:

7.53MB of 9.53MB total (79.00%)
Dropped 234 nodes (cum <= 0.05MB)
Showing top 5 nodes out of 28 (cum >= 1MB)
      flat  flat%   sum%        cum   cum%
       2MB 21.00% 21.00%        2MB 21.00%  strings.Replace
    1.51MB 15.89% 36.89%     1.51MB 15.89%  github.com/PolkaSpots/worker/worker.func·006
    1.51MB 15.87% 52.76%     1.51MB 15.87%  github.com/PolkaSpots/worker/worker.func·008
    1.50MB 15.75% 68.51%     1.50MB 15.75%  newproc_m
       1MB 10.50% 79.00%        1MB 10.50%  gopkg.in/mgo.v2/bson.(*decoder).readStr

是否有更有效/推荐的方法来实现这一目标?

EDIT_

按照建议,我已经改变了循环

    done := make(chan bool)

    go func() {
        for {
            select {
            case client := <-c1:
                array = append(array, client)
                macs = append(macs, client.Client_Mac)
            case <-done:
                return
            }
        }
    }()

    wg.Wait()
    close(done)

最佳答案

接收循环永不中断:

  for {
            select {
            case client := <-c1:
            ...
   }

它没有停止条件,没有超时,什么都没有——所以它会永远卡在那里——即使你的整个函数都退出了。它会泄漏 goroutine 和 channel 。

最重要的是,当此循环退出时,您推迟了 wg.Done,但您没有执行 wg.Add 来匹配它。因此,如果此循环退出,您将感到 panic 。

您需要做的是找到某种方法来停止 for/select 循环。 IMO 最简单的方法 - 在 wg.Wait() 之后添加第二个接收数据的 channel ,但不要在该 goroutine 中执行 wg.Done()

关于memory-leaks - Golang WaitGroup导致内存泄漏,我该怎么做才能改进这个功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31942770/

相关文章:

c++ - 无法在 gRPC 中使用 proto 3.0 缓冲区生成客户端代码

c# - 防止 Autofac 持有一次性实例

c++ - 模板化动态数组上的内存泄漏

go - Go 中通过和失败的测试用例列表

postgresql - pgx lib中的命名准备语句,它是如何工作的?

http - 如何为 Golang HTTP 请求发送嵌套 header

json - 多个 map[string] 接口(interface)并将它们映射到多个 json 文件 GOLANG

iphone - iOS SDK : Adding AVCaptureVideoDataOutput to AVCaptureSession causes it to slowly leak memory indefinitely

javascript - 什么时候使用 JavaScript 模板引擎?

python - Tensorflow 在每次调用带有最终图的 session.run() 时泄漏内存