使用pprof发现内存泄漏
【译文】原文地址
Golang是一个很神奇的语言。在开发系统应用或web应用时候,建议考虑采用Golang。Golang开发者的需求持续增长也是一个很好的证明。
通过分析利弊我尝试了Go。我们有特定的使用场景,需要超低的构建时间,同时尽可能少使用资源。并且,我们使用微服务架构,因此可能使用不同的技术栈而不是单一的一种。
总的来说,Golang+Graphql性能挺好的。每秒能处理大量的请求。正常请求和负载不会有问题。当我们使用压测和性能测试脚本的时候问题出现了。
起初,我们发现应用异常是在大负载情况下。我们持续监测资源,性能测试完一段时间后,我们的服务使用了集群的大量资源(CPU和内存)。这使我们很沮丧和害怕因为没有达到我们使用GO的初衷。因此,我们分析发现问题并不是Golang语言问题,而是我们代码的bug。
下面聊聊pprof
来自pprof Github仓库 Github repo.)的简单介绍:
pprof是一个用于对收集的数据分析和可视化工具。pprof从profile.proto文件读取收集的样本数据,并生成可视化的报告便于对数据进行分析。可以生成文本和图像报告。
pprof详细文档链接。只需使用很少代码即可使用pprof。在生产环境中使用pprof也是安全的,它最大只需要5%的资源消耗。
使用pprof
使用pprof工具,生成了内存和cpu的使用统计图(下面PNG格式图片)。一眼看去很明显发现amqp_helper(队列处理文件)存在问题。我分析了代码,发现amqp连接没有关闭,导致内存占用。
图中框越大说明占有资源越多。
如何解决
我推荐检查pprof.go的init()函数。将有助于理解/debug/pprof路由。使用如下模版:
package main
import (
"net/http"
"net/http/pprof"
)
func main() {
// other code
// if your app is not serving on any port
// then create a simple webserver
go func() {
log.Println(http.ListenAndServe("localhost:8082", nil))
}()
}
当你访问http://localhost:8082/debug,可以看到go提供各种资源使用统计。
生成图表
保持前面程序运行,执行如下命令生成图表:
1、内存统计
go tool pprof -png http://localhost:8082/debug/pprof/heap > heap.png
该命令会在当前目录生成heap.png文件。
2、CPU统计
go tool proof -png http://localhost:8082/debug/pprof/profile > profile.png
以下是一个CPU统计的图表示例。使用上述命令,你可以创建和分析不同的统计数据。
常见内存泄漏
1、没有正确的关闭或未关闭连接。包括数据库连接,队列连接,第三方库。
2、没有正确使用defer()函数
3、使用大字符串/切片/子序列对其做多次操作。
4、指针音乐不使用的值
5、悬挂Goroutine
6、误用Finalizer