我试图找到内存泄漏,我已将其归零到这部分代码,但我找不到内存泄漏的位置或如何修复它,当我让一些人调查时他们建议它与此处提到的“代码”有关: 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/