我这是为了监控一些网站,如果其中一个网站出现故障通知我。我只在两个网址上测试它。当它启动时它使用大约5mb的内存(我用systemctl status monitor
检查)。 40分钟后,它使用7.4mb。 8小时后,它使用超过50mb的内存。它为什么这样做?这称为内存泄漏吗?
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\n", err)
os.Exit(0)
}
err = yaml.Unmarshal(data, &config)
if err != nil {
fmt.Printf("Invalid config: %s\n", 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)
}
}
}
如果这属于Code Review,那么我会把它放在那里。
答案 0 :(得分:6)
是的,这是内存泄漏。我能发现的一个明显的来源是你没有从你的请求中关闭响应主体:
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)
}
}
}
更好的是,Go可以使用keepalive,你想阅读全身并关闭它:
defer func() {
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
}()
通过使用pprof
对应用程序进行概要分析,您可以进一步分析内存使用的来源。有a good rundown on the Go blog,网络搜索会发出更多关于该主题的文章。