背景
写个后台程序,定时抓取服务器指标,代码逻辑如下,使用一段时间后内存不断增加
func CollectInfo() {
for {
// 获取服务器信息代码
// ...............
resp, err := http.Post("http://server", "application/json", strings.NewReader(`{"info1": "xxxx", "info2": "yyyy"}`))
if err != nil {
// 错误处理
}
defer resp.Body.Close()
// 处理其他逻辑
time.Sleep(time.Minute)
}
}
排查
一开始感觉是哪里文件或者网络忘记Close了,看下进程打开的文件.
如下图类似情况, 看到很多http ESTABLISHED状态,估计就是哪个http忘记Close.
排查代码,问题应该出现在上面一段代码,for循环中defer不会执行,在函数返回时执行
# 查看进程打开的文件
lsof -p `pgrep defer`
验证
写个例子测试一下
package main
import (
"log"
"time"
)
func main() {
log.Println("program started")
for i := 0; i < 3; i++ {
defer func(i int) {
log.Println("defer executed: ", i)
}(i)
}
time.Sleep(time.Minute)
log.Println("program exited")
}
根据打印的时间,可以得出以下两条结论
defer只在函数返回时才执行
defer执行顺序是先进后出,先调用的后执行
优化
写defer写习惯了,这里不能用defer, 用完直接调用关闭
func CollectInfo() {
for {
// 获取服务器信息代码
// ...............
resp, err := http.Post("http://server", "application/json", strings.NewReader(`{"info1": "xxxx", "info2": "yyyy"}`))
if err != nil {
// 错误处理
} else{
resp.Body.Close()
}
// 处理其他逻辑
time.Sleep(time.Minute)
}
}