Logging GoLang数据记录器(带宽)内存泄漏

Logging GoLang数据记录器(带宽)内存泄漏,logging,go,Logging,Go,我正试图找到内存泄漏,我已经将其归零到代码的这一部分,但我找不到内存泄漏的位置或如何修复它,当我让一些人研究它时,他们建议它与这里提到的股票代码有关: 它漏了。有关于修复的想法吗 谢谢 package main import ( "bufio" "encoding/csv" "fmt" "log" "os" "time" ) // Records information about a transfer window: the total am

我正试图找到内存泄漏,我已经将其归零到代码的这一部分,但我找不到内存泄漏的位置或如何修复它,当我让一些人研究它时,他们建议它与这里提到的股票代码有关: 它漏了。有关于修复的想法吗

谢谢

package main

import (
    "bufio"
    "encoding/csv"
    "fmt"
    "log"
    "os"
    "time"
)

// Records information about a transfer window: the total amount of data
// transferred in a fixed time period in a particular direction (clientbound or
// serverbound) in a session.
type DataLoggerRecord struct {
    // Number of bytes transferred in this transfer window.
    Bytes uint
}

var DataLoggerRecords = make(chan *DataLoggerRecord, 64)

// The channel returned should be used to send the number of bytes transferred
// whenever a transfer is done.
func measureBandwidth() (bandwidthChan chan uint) {
    bandwidthChan = make(chan uint, 64)
    timer := time.NewTicker(config.DL.FlushInterval * time.Second)

    go func() {
        for _ = range timer.C {
            drainchan(bandwidthChan)
        }
    }()  

    go func() {
        var count uint
        ticker := time.Tick(config.DL.Interval)

        for {
            select {
            case n := <-bandwidthChan:
                count += n

            case <-ticker:
                DataLoggerRecords <- &DataLoggerRecord{
                    Bytes:      count,
                }
                count = 0
            }
        }
    }()

    return bandwidthChan
}

func drainchan(bandwidthChan chan uint) {
    for {
        select {
        case e := <-bandwidthChan:
            fmt.Printf("%s\n", e)
        default:
            return
        }
    }
}


func runDataLogger() {
    f, err := os.OpenFile(dataloc, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        log.Fatalf("[DL] Could not open %s", err.Error())
    }

    bw := bufio.NewWriter(f)
    defer func() {
        bw.Flush()
        f.Close()
    }()

    go func() {
        for {
            time.Sleep(time.Second)
            bw.Flush()
        }
    }()

    w := csv.NewWriter(bw)


    for record := range DataLoggerRecords {
        if record.Bytes != 0 {
            err = w.Write([]string{
                fmt.Sprintf("%d", record.Bytes),
            })
            w.Flush()
        } else {
            continue
        }
    }
    if err != nil {
        if err.Error() != "short write" {
            log.Printf("[DL] Failed to write record: %s", err.Error())
        } else {
            w.Flush()
        }
    }
}
你正在开始2次。滴答答,从不停止他们,并开始2个永不返回的goroutines。每次调用measureBandwidth都会泄漏这些资源

因为你已经有了一个你只在上面接收的频道,你应该用它作为一个信号从计数goroutine返回。然后调用方将关闭返回的通道以进行清理

第二个goroutine是不需要的,它只用于与计数器竞争以丢弃值。计数goroutine可以继续,如果发送到记录器的速度太慢,请将其放在自己的select case中

func measureBandwidth() (bwCh chan int) {
    bwCh = make(chan int, 64)

    go func() {
        ticker := time.NewTicker(config.DL.Interval)
        defer ticker.Stop()

        count := 0

        for {
            select {
            case n, ok := <-bwCh:
                if !ok {
                    return
                }
                count += n

            case <-ticker.C:
                DataLoggerRecords <- &DataLoggerRecord{Bytes: count}
                count = 0
            }
        }
    }()

    return bwCh
}
例如:


次要的挑剔,通常更倾向于使用有符号类型来操作这样的数值:参见此处的一个对话:

您的代码未编译:抱歉,它是更大项目的一部分,这只是引用的代码的一部分,因此没有主函数我不知道使用它的上下文,但是measureBandwidth创建了两个永不停止的标记器,并启动了两个永不返回的goroutine。如果您反复调用它,您将泄漏这些资源。@JimB我们运行它是为了做带宽记录,它是通过函数调用的,所以是的,它们经常被调用;然而,我将如何着手解决这个问题呢?