go程序内存打满之goroutine泄露溢出之http的response.Body 未关闭
一段程序跑了一天一夜,内存打爆了。排查代码自己写的创建 goroutine 代码无持续性,且有退出机制。
使用
使用 pprof 工具排查
https://blog.csdn.net/kenkao/article/details/96300389
package main import ( "bytes" "fmt" "net/http" _ "net/http/pprof" //查看内存占用使用 "net/url" "time" ) func main() {//测试不关闭response.body //_ "net/http/pprof" //查看内存占用使用 访问http://127.0.0.1:12345/debug/pprof/查看内存申请和 goroutine 创建数量 // pprof 的init函数会将pprof里的一些handler注册到http.DefaultServeMux上 // 当不使用http.DefaultServeMux来提供http api时,可以查阅其init函数,自己注册handler go func() { fmt.Println("http.ListenAndServe(\"0.0.0.0:12348\" befor, nil)") http.ListenAndServe("0.0.0.0:12348", nil) fmt.Println("http.ListenAndServe(\"0.0.0.0:12348\" after, nil)") }() for { addr := "https://www.baidu.com" urlObj, _ := url.Parse(addr) fmt.Println(urlObj.String()) request, err := http.NewRequest("GET", urlObj.String(), bytes.NewBuffer([]byte{})) fmt.Println("request.Body:", request.Body) defer request.Body.Close() if err != nil { fmt.Println("http.NewRequest:", err) } r, err := http.DefaultClient.Do(request) //***********核心代码,如果不关闭Body,则产生的goroutine不释放********************* // 解决方式一、r.Body.Close() if r.Body != nil { r.Body.Close() } // 解决方式二、将.Body内容全部读取,由io.ReadAll()实现关闭 //recvBytes, err := io.ReadAll(r.Body) //bodyStr := string(recvBytes) //fmt.Println(bodyStr) fmt.Println("r.status:", r.StatusCode, r.Status) time.Sleep(time.Second) } }
response.Body不关闭时,查看goroutine 数量每次请求都会+2
关闭后保持稳定状态
另有发现老文章:https://zhuanlan.zhihu.com/p/391917096
posted on 2023-02-26 23:00 zhangmingda 阅读(187) 评论(0) 编辑 收藏 举报