dongying3744 2017-12-14 16:37
浏览 323
已采纳

为什么此Golang应用程序运行的时间越长会占用更多的内存?

I made this to monitor a few websites and notify me if one of them goes down. I'm testing it on just two urls. When it starts it uses about 5mb of memory (I checked with systemctl status monitor). After 40 minutes, it's using 7.4mb. After 8 hours, it uses over 50mb of memory. Why is it doing this? Is this called a memory leak?

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "sync"
    "time"

    "monitor/utils/slack"

    "gopkg.in/yaml.v2"
)

var config struct {
    Frequency int
    Urls      []string
}

type statusType struct {
    values map[string]int
    mux    sync.Mutex
}

var status = statusType{values: make(map[string]int)}

func (s *statusType) set(url string, value int) {
    s.mux.Lock()
    s.values[url] = value
    s.mux.Unlock()
}

func init() {
    data, err := ioutil.ReadFile("config.yaml")
    if err != nil {
        fmt.Printf("Invalid config: %s
", err)
        os.Exit(0)
    }

    err = yaml.Unmarshal(data, &config)
    if err != nil {
        fmt.Printf("Invalid config: %s
", err)
        os.Exit(0)
    }

    for _, url := range config.Urls {
        status.set(url, 200)
    }
}

func main() {
    ticker := time.NewTicker(time.Duration(config.Frequency) * time.Second)
    for _ = range ticker.C {
        for _, url := range config.Urls {
            go check(url)
        }
    }
}

func check(url string) {
    res, err := http.Get(url)
    if err != nil {
        res = &http.Response{StatusCode: 500}
    }

    // the memory problem occurs when this condition is never satisfied, so I didn't post the slack package.
    if res.StatusCode != status.values[url] {
        status.set(url, res.StatusCode)

        err := slack.Alert(url, res.StatusCode)
        if err != nil {
            fmt.Println(err)
        }
    }
}

If this belongs in Code Review then I will put it there.

  • 写回答

1条回答 默认 最新

  • douzhongjian0752 2017-12-14 16:39
    关注

    Yes, this is a memory leak. One obvious source I can spot is that you're not closing the response bodies from your requests:

    func check(url string) {
        res, err := http.Get(url)
        if err != nil {
            res = &http.Response{StatusCode: 500}
        } else {
            defer res.Body.Close()    // You need to close the response body!
        }
    
        if res.StatusCode != status.values[url] {
            status.set(url, res.StatusCode)
    
            err := slack.Alert(url, res.StatusCode)
            if err != nil {
                fmt.Println(err)
            }
        }
    }
    

    Better still, so that Go can use keepalive, you want to read the full body and close it:

    defer func() {
        io.Copy(ioutil.Discard, res.Body)
        res.Body.Close()
    }()
    

    You can further analyse where memory usage is coming from by profiling your application with pprof. There's a good rundown on the Go blog and a web search will turn up many more articles on the topic.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 matlab有关常微分方程的问题求解决
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?
  • ¥100 求三轴之间相互配合画圆以及直线的算法
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable