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.

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

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度