2016-03-09 26 views
-2

我試圖找到內存泄漏,我已經歸零到這部分的代碼,但我找不到內存泄漏或如何解決它,當我有人看着它,他們建議它與這裏提到的「代理人」有關: https://golang.org/src/time/tick.go 它「泄漏」。任何想法修復?GoLang數據記錄器(帶寬)內存泄漏

謝謝! :)

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

您的代碼不編譯:[如何創建一個最小,完整和可驗證的示例。](http://stackoverflow.com/help/mcve) – peterSO

+0

對不起,它是大型項目的一部分,這只是引用的代碼的一部分(因此沒有主要功能) –

+1

我不知道使用它的上下文,但'measureBandwid th'創建2個永不停止的tickers,並啓動2個永不返回的goroutines。如果你反覆打電話,你會「泄漏」這些資源。 – JimB

回答

0

你開始2 time.Ticker並永不停止它們,並啓動2個goroutines永遠不會返回。每當您撥打measureBandwidth時,您都會「泄漏」這些資源。

由於您已經擁有了一個您只能接收的頻道,因此您應該使用該頻道作爲返回計數參數的信號。呼叫者然後關閉返回的頻道進行清理。

第二個例程不需要,只用於比賽櫃檯扔掉價值。計數參數可以保持不變,如果發送給記錄器速度太慢,請將其放入自己的選擇案例中。

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?