goroutine泄露
这里所说的Go内存泄露是指goroutine泄露。如果你启动了1个goroutine,但并没有符合预期的退出,直到程序结束,此goroutine才退出,这种情况就是goroutine泄露。在此之前先来认识一下pprof,pprof是Go的性能分析工具,在程序运行过程中,可以记录程序的运行信息,可以是CPU使用情况、内存使用情况、goroutine运行情况等。
Go已经有一个封装好的net/http/pprof
,使用简单的几行命令,就可以开启pprof,记录运行信息,并且提供了Web服务。
如果一个存在的Go内存泄露情况如下:
http://xxxx/debug/pprof/
allocs:所有过去内存分配的样本
block:导致同步阻塞的堆栈跟踪
cmdline:当前程序的命令行调用
goroutine:所有当前 goroutine 的堆栈跟踪
heap:活动对象的内存分配示例。 您可以指定 gc GET 参数以在获取堆样本之前运行 GC。
mutex:竞争互斥体持有者的堆栈跟踪
profile:CPU 配置文件。 您可以在 seconds GET 参数中指定持续时间。 获取配置文件后,使用 go tool pprof 命令调查配置文件。
threadcreate:导致创建新操作系统线程的堆栈跟踪
trace:当前程序执行的轨迹。 您可以在 seconds GET 参数中指定持续时间。 获取跟踪文件后,使用 go tool trace 命令调查跟踪。
比如点一个cmdline,查看运行的命令,也许会包括账号密码。
/debug/pprof/cmdline?debug=1
点击profile或者trace的时候会下载一个编译的文件,里面含有进程信息以及程序信息。使用如下命令查看,可以看到这是一个so文件。
go tool pprof .\profile
# go tool pprof http://xxx/profile
查看进程函数占用,查看命令介绍可以使用help。
也可以下载heap查看,需要删掉链接上自动带的debug=1。
这个heap文件写的是什么
/debug/pprof/goroutine?debug=1
大概能看出来的是有62个goroutine被挂起,不能退出。这里面有6个goroutine挂在了wss_client.go的104行。
pprof分析
先安装一个graphviz:https://graphviz.gitlab.io/_pages/Download/Download_windows.html
go tool pprof --http=":8999" https://xxxx/debug/pprof/heap
颜色越深越大的代表占用和耗时越多
goroutine 泄露的场景
goroutine泄露的本质是channel阻塞,无法继续向下执行,导致此goroutine关联的内存都无法释放,进一步造成内存泄露。
- channel的读或者写:
- 无缓冲channel的阻塞通常是写操作因为没有读而阻塞
- 有缓冲的channel因为缓冲区满了,写操作阻塞
- 期待从channel读数据,结果没有goroutine写
- select操作,select里也是channel操作,如果所有case上的操作阻塞,goroutine也无法继续执行。
参考文章: