- 首先看一个示例:
import(
"_net/http/pprof"
"sync"
)
var wg sync.WaitGroup
func main() {
go func() {
http.ListenAndServe("127.0.0.1:8090", nil)
}()
c := make(chan struct{})
wg.Add(1)
for i:=0;i<10000;i++{
go leak(c)
wg.Done()
}
fmt.Println("xxxx结束!",len(a))
wg.Wait()
}
func leak(c chan struct{}){
a := make([]int64,0)
for i := 0; i < 10000; i++ {
a = append(a, rand.Int63())
}
<-c
}
- 1 win10系统安装graphviz这个的MSI包,下载地址:(https://graphviz.gitlab.io/_pages/Download/windows/graphviz-2.38.msi),配置好环境变量后启动程序就能在浏览器打开下面的页面,程序绑定了localhost地址:(http://127.0.0.1:8090/debug/pprof/)
-
2 上面程序是通过结构体阻塞了程序,开启了10000个协程,GC没有回收,导致内存一直占用,通过Go内置包pprof可以看到,有开启了10004个协程,堆区分配了19次内存。这很明显GC没有回收掉这部分的协程内存,
image.png - 3 下面把程序改动下,看内存回收情况
var wg sync.WaitGroup
func main() {
go func() {
http.ListenAndServe("127.0.0.1:8090", nil)
}()
wg.Add(1)
for i:=0;i<10000;i++{
go leak()
}
wg.Wait()
}
func leak(){
a := make([]int64,0)
for i := 0; i < 10000; i++ {
a = append(a, rand.Int63())
}
time.Sleep(time.Second * 1)
}
image.png
- 4 程序没有结束一直占着内存,但是goroutine却大幅下降了,runtime已经回收掉部分内存了,只是程序还有点问题没有结束,改下。测试程序的时候通过检测goroutine可以验证是否有内存泄露问题存在。再CMD下输入:go tool pprof -http :8081 把http://127.0.0.1:8090/debug/pprof/heap 在浏览器输入能更直观的看到程序占用资源的情况分布。
image.png