最近在项目中出现golang内存溢出的问题,master刚开始运行时只有10多M,运行几天后,居然达到了10多个G。并且到凌晨流量变少内存也没有明显下降,内存状态呈现一种很不健康的曲线。golang
像这种状况确定是golang内存溢出了,为此我持续排查了两天,终于找到问题所在,特此记录下。web
将master引入net/http/pprof包,经过http访问得到goroutine、heap信息。浏览器
//引入pprof import _"net/http/pprof" //在main中加入 go func() { log.Println(http.ListenAndServe("localhost:9999", nil)) }()
浏览器访问: http://127.0.0.1:9999/debug/pprof/
获取goroutine信息 http://10.13.132.91:9999/debug/pprof/goroutine?debug=2
获取heap信息 http://10.13.132.91:9999/debug/pprof/heap?debug=2
使用golang tool进行统计分析,go tool pprof -inuse_space http://127.0.0.1:9999/debug/pprof/heap
。输入top10能够看出前十占用内存状况,这里我是直接输入png导出图片来查看,以便之后比较。还有两个参数能够选择,-inuse_space顾名思义是正在使用的内存,-alloc_space是已经分配的内存,本次我是一直用-inuse_space进行分析。websocket
go是一门本身gc的语言,大概两分钟会gc一次。若是有内存泄漏,无非就是两种状况。数据结构
首先,我利用压测工具对server进行100个websocket链接,模拟用户浏览行为,而后关闭链接。打开浏览器查看goroutine数量,发现新起的goroutine所有已经销毁,没有观察到有泄漏的goroutine,所以排除此状况。socket
排除goroutine泄漏,只能是由全局状态变量引发的。再次用压测工具进行压测而后关闭,使用观察内存状况。使用go tool pprof -inuse_space http://127.0.0.1:9999/debug/pprof/heap
输入png
导出(在这种状况下,须要等程序gc完再导出,建议等10分钟左右。)
发现问题所在
每次都会遗留这么大概0.5M的内存空间出来,就奇怪,明明整个goroutine退出为何还有会内存占用?相应的全局变量也会删除该地方的引用。等一下,全局变量,难道是删除的时候没作好配对致使没有真正删除该引用吗?去查了下代码,果真是没有删除引用致使的,至此问题解决。
这里面有个项目的坑,上报日志的key不是根据这个len(map)
计算出,致使上报日志的时候觉得删除了该key。工具
为何会花了两天时间,看起来上述流程并不复杂。测试