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

标签 logging go

我试图找到内存泄漏,我已将其归零到这部分代码,但我找不到内存泄漏的位置或如何修复它,当我让一些人调查时他们建议它与此处提到的“代码”有关: https://golang.org/src/time/tick.go 它“泄漏”。关于修复有什么想法吗?

谢谢! :)

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 个 time.Ticker 并且从不停止它们,并且启动了 2 个永不返回的 goroutine。每次调用 measureBandwidth 时,您都会“泄漏”这些资源。

由于您已经有了一个仅用于接收的 channel ,因此您应该将其用作从计数 goroutine 返回的信号。然后,调用者将关闭返回的 channel 以进行清理。

第二个 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
}

示例:http://play.golang.org/p/RfpBxPlGeW

(小吹毛求疵,通常首选使用带符号的类型来操作数值,如下所示:请参阅此处的此类对话:When to use unsigned values over signed ones?)

关于logging - GoLang 数据记录器(带宽)内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35880960/

相关文章:

java - 在 Android Studio logcat 中显示 java.util.logging.Logger 日志

git - 如何在 git 日志图中显示相对提交号?

记录 Rust 程序

go - 如何在不使用 cgo 的情况下将 Go 函数绑定(bind)到 C 调用?

go - 使用gocql的cassandra查询中的可变参数

logging - 如何从 TaskScheduler 运行的脚本重定向 Powershell 输出并覆盖 80 个字符的默认宽度

java - 如何将 Java 控制台输出通过管道传输到文件?

go - 如何在 gval 表达式中添加引号

go - 如何订购为网关及其成员配置 ssh 的软层网络网关

amazon-web-services - 将 cmd 文件夹中的 golang 应用程序部署到 AWS Beanstalk