Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang 内存分析/内存泄漏

golang 内存分析/内存泄漏

作者头像
ppxai
发布于 2020-09-23 09:48:59
发布于 2020-09-23 09:48:59
9.5K00
代码可运行
举报
文章被收录于专栏:皮皮星球皮皮星球
运行总次数:0
代码可运行

pprof

pprof 是 Go 语言中分析程序运行性能的工具,它能提供各种性能数据:

类型

描述

allocs

内存分配情况的采样信息

blocks

阻塞操作情况的采样信息

goroutine

当前所有协程的堆栈信息

heap

堆上内存的使用情况的采样信息

profile

CPU占用情况的采样信息

threadcreate

系统线程创建情况的采样信息

trace

程序运行跟踪信息

以内存分析为例:

推荐直接使用命令进入命令行交互模式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go tool pprof -alloc_space http://localhost:6061/debug/pprof/heap

可以使用参数指明分析的类型:

inuse_space — amount of memory allocated and not released yet inuse_objects— amount of objects allocated and not released yet alloc_space — total amount of memory allocated (regardless of released) alloc_objects — total amount of objects allocated (regardless of released)

进入交互式模式之后,比较常用的有 top、list、traces、web 等命令。

(1) top

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(pprof) top
Showing nodes accounting for 15624.87MB, 50.48% of 30953.89MB total
Dropped 229 nodes (cum <= 154.77MB)
Showing top 10 nodes out of 167
flat  flat%   sum%        cum   cum%
6272.15MB 20.26% 20.26%  6272.15MB 20.26%  github.com/emicklei/go-restful.CurlyRouter.selectRoutes
1457.12MB  4.71% 30.48%  1457.12MB  4.71%  bytes.makeSlice
1177.26MB  3.80% 38.47%  1260.76MB  4.07%  net/textproto.(*Reader).ReadMIMEHeader
900.41MB  2.91% 41.38%   987.41MB  3.19%  google.golang.org/grpc/internal/transport.(*http2Client).createHeaderFields
780.13MB  2.52% 43.90%  3044.06MB  9.83%  net/http.(*conn).readRequest
705.24MB  2.28% 46.18%   705.24MB  2.28%  github.com/emicklei/go-restful.sortableCurlyRoutes.routes
678.09MB  2.19% 48.37%  1112.62MB  3.59%  google.golang.org/grpc/internal/transport.(*http2Client).newStream
653.03MB  2.11% 50.48%   653.03MB  2.11%  context.WithValue

top会列出5个统计数据:

  • flat: 本函数占用的内存量。
  • flat%: 本函数内存占使用中内存总量的百分比。
  • sum%: 前面每一行flat百分比的和,比如第2行虽然的100% 是 100% + 0%。
  • cum: 是累计量,加入main函数调用了函数f,函数f占用的内存量,也会记进来。
  • cum%: 是累计量占总量的百分比。

(2) list

查看某个函数的代码,以及该函数每行代码的指标信息,如果函数名不明确,会进行模糊匹配,比如

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(pprof) list github.com/emicklei/go-restful.CurlyRouter.selectRoutes
Total: 30.45GB
ROUTINE ======================== github.com/emicklei/go-restful.CurlyRouter.selectRoutes in /Users/michaelliu/go/pkg/mod/github.com/emicklei/go-restful@v2.12.0+incompatible/curly.go
6.13GB     6.13GB (flat, cum) 20.11% of Total
.          .     43:	return detectedService, selectedRoute, nil
.          .     44:}
.          .     45:
.          .     46:// selectRoutes return a collection of Route from a WebService that matches the path tokens from the request.
.          .     47:func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes {
6.06GB     6.06GB     48:	candidates := make(sortableCurlyRoutes, 0, 8)
.          .     49:	for _, each := range ws.routes {
.          .     50:		matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens, each.hasCustomVerb)
.          .     51:		if matches {
.          .     52:			candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers?
.          .     53:		}
.          .     54:	}
64.50MB    64.50MB     55:	sort.Sort(candidates)
.          .     56:	return candidates
.          .     57:}
.          .     58:
.          .     59:// matchesRouteByPathTokens computes whether it matches, howmany parameters do match and what the number of static path elements are.
.          .     60:func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []string, routeHasCustomVerb bool) (matches bool, paramCount int, staticCount int) {

可以看到在github.com/emicklei/go-restful.CurlyRouter.selectRoutes中的第48行占用了6.06GB内存。

(3) traces

traces可以打印所有调用栈,以及调用栈的指标信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(pprof) traces github.com/emicklei/go-restful.CurlyRouter.selectRoutes
Type: alloc_space
Time: Sep 20, 2020 at 7:39pm (CST)
-----------+-------------------------------------------------------
bytes:  32B
64.50MB   github.com/emicklei/go-restful.CurlyRouter.selectRoutes
github.com/emicklei/go-restful.CurlyRouter.SelectRoute
github.com/emicklei/go-restful.(*Container).dispatch.func3
github.com/emicklei/go-restful.(*Container).dispatch
net/http.HandlerFunc.ServeHTTP
net/http.(*ServeMux).ServeHTTP
github.com/emicklei/go-restful.(*Container).ServeHTTP
net/http.serverHandler.ServeHTTP
net/http.(*conn).serve
-----------+-------------------------------------------------------
bytes:  3kB
6.06GB   github.com/emicklei/go-restful.CurlyRouter.selectRoutes
github.com/emicklei/go-restful.CurlyRouter.SelectRoute
github.com/emicklei/go-restful.(*Container).dispatch.func3
github.com/emicklei/go-restful.(*Container).dispatch
net/http.HandlerFunc.ServeHTTP
net/http.(*ServeMux).ServeHTTP
github.com/emicklei/go-restful.(*Container).ServeHTTP
net/http.serverHandler.ServeHTTP
net/http.(*conn).serve
-----------+-------------------------------------------------------

每个- - - - - 隔开的是一个调用栈。

内存泄露

内存泄露指的是程序运行过程中已不再使用的内存,没有被释放掉,导致这些内存无法被使用,直到程序结束这些内存才被释放的问题。

内存profiling记录的是堆内存分配的情况,以及调用栈信息,并不是进程完整的内存情况。基于抽样和它跟踪的是已分配的内存,而不是使用中的内存,(比如有些内存已经分配,看似使用,但实际以及不使用的内存,比如内存泄露的那部分),所以不能使用内存profiling衡量程序总体的内存使用情况。

只能通过heap观察内存的变化,增长与减少,内存主要被哪些代码占用了,程序存在内存问题,这只能说明内存有使用不合理的地方,但并不能说明这是内存泄露。

heap在帮助定位内存泄露原因上贡献的力量微乎其微。能通过heap找到占用内存多的位置,但这个位置通常不一定是内存泄露,就算是内存泄露,也只是内存泄露的结果,并不是真正导致内存泄露的根源。

(1)怎么用heap发现内存问题

使用pprof的heap能够获取程序运行时的内存信息,在程序平稳运行的情况下,每个一段时间使用heap获取内存的profile,然后使用base能够对比两个profile文件的差别,就像diff命令一样显示出增加和减少的变化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
➜  pprof go tool pprof -alloc_space -base pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.149.pb.gz pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.150.pb.gz
Type: alloc_space
Time: Sep 20, 2020 at 7:23pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 221.95MB, 97.36% of 227.97MB total
Dropped 51 nodes (cum <= 1.14MB)
Showing top 10 nodes out of 55
flat  flat%   sum%        cum   cum%
199.29MB 87.42% 87.42%   199.29MB 87.42%  bytes.makeSlice
9.52MB  4.17% 91.59%     9.52MB  4.17%  regexp/syntax.(*compiler).inst (inline)
2.64MB  1.16% 92.75%     2.64MB  1.16%  compress/flate.NewWriter
2.50MB  1.10% 93.85%     4.50MB  1.97%  regexp/syntax.(*Regexp).Simplify
2MB  0.88% 94.73%        2MB  0.88%  regexp/syntax.simplify1 (inline)
2MB  0.88% 95.61%        2MB  0.88%  time.NewTimer
1.50MB  0.66% 96.26%     1.50MB  0.66%  os.lstatNolog
1.50MB  0.66% 96.92%     1.50MB  0.66%  regexp/syntax.(*parser).newRegexp (inline)
0.50MB  0.22% 97.14%     1.50MB  0.66%  github.com/go-chassis/go-chassis/pkg/scclient.(*RegistryClient).HTTPDo
0.50MB  0.22% 97.36%    16.01MB  7.02%  regexp.compile
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(pprof) traces bytes.makeSlice
Type: alloc_space
Time: Sep 20, 2020 at 7:23pm (CST)
-----------+-------------------------------------------------------
bytes:  199.29MB
199.29MB   bytes.makeSlice
bytes.(*Buffer).grow
bytes.(*Buffer).Grow
io/ioutil.readAll
io/ioutil.ReadFile
github.com/go-chassis/go-chassis/core/lager.CopyFile
github.com/go-chassis/go-chassis/core/lager.doRollover
github.com/go-chassis/go-chassis/core/lager.logRotateFile
github.com/go-chassis/go-chassis/core/lager.LogRotate
github.com/go-chassis/go-chassis/core/lager.(*rotators).Rotate.func1
-----------+-------------------------------------------------------
bytes:  613.91MB
0   bytes.makeSlice
bytes.(*Buffer).grow
bytes.(*Buffer).ReadFrom
io/ioutil.readAll
io/ioutil.ReadFile
github.com/go-chassis/go-chassis/core/lager.CopyFile
github.com/go-chassis/go-chassis/core/lager.doRollover
github.com/go-chassis/go-chassis/core/lager.logRotateFile
github.com/go-chassis/go-chassis/core/lager.LogRotate
github.com/go-chassis/go-chassis/core/lager.(*rotators).Rotate.func1
-----------+-------------------------------------------------------
bytes:  306.95MB
0   bytes.makeSlice
bytes.(*Buffer).grow
bytes.(*Buffer).Grow
io/ioutil.readAll
io/ioutil.ReadFile
github.com/go-chassis/go-chassis/core/lager.CopyFile
github.com/go-chassis/go-chassis/core/lager.doRollover
github.com/go-chassis/go-chassis/core/lager.logRotateFile
github.com/go-chassis/go-chassis/core/lager.LogRotate
github.com/go-chassis/go-chassis/core/lager.(*rotators).Rotate.func1
-----------+-------------------------------------------------------

(2)goroutine泄露怎么导致内存泄露

每个goroutine占用2KB内存,泄露1百万goroutine至少泄露2KB * 1000000 = 2GB内存。此外goroutine执行过程中还存在一些变量,如果这些变量指向堆内存中的内存,GC会认为这些内存仍在使用,不会对其进行回收,这些内存谁都无法使用,造成了内存泄露。

所以goroutine泄露有2种方式造成内存泄露:

  • goroutine本身的栈所占用的空间造成内存泄露。
  • goroutine中的变量所占用的堆内存导致堆内存泄露,这一部分是能通过heap profile体现出来的。

分析goroutine本身的栈所占用的空间造成内存泄露,可以通过pprof来查找,方法与heap类似,都是取两次采样做比较。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020年09月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
生产环境Go程序内存泄露,用pprof如何快速定位
内存泄漏可以在整个系统中以多种形式出现,除了在写代码上的疏忽,忘了关闭该关闭的资源外,更多的时候导致系统发生内存泄露原因可能是设计上决策不对、或者业务逻辑上的疏忽没有考虑到一些边界条件。
KevinYan
2022/02/10
4.4K0
Golang使用pprof监控性能及GC调优
作者:峰云就她了 链接:http://xiaorui.cc/?p=3000 來源:个人博客 共 8809 字,阅读需 22 分钟 这两天用golang在写一个监控的agent,发现长时间运行后会有内存
李海彬
2018/07/26
4K0
Golang使用pprof监控性能及GC调优
【实践】使用Go pprof做内存性能分析
阿里云Redis线上在某些任务流中使用redis-port来进行实例之间的数据同步。redis-port是一个MIT协议的开源软件,主要原理是从源实例读取RDB快照文件、解析、然后在目标实例上应用灌数据的写命令。为了限制每个进程的最大内存使用,我们使用cgroup来做隔离,最近线上出现redis-port在同步数据时OOM的情况,最高内存使用达到了10G以上,而实际RDB的大小只有4.5GB左右。
辉哥
2019/08/18
22.3K0
golang pprof
当正在运行的golang程序消耗预期之外的内存和时间,我们这个时候就需要去弄明白,到底是是我们的代码哪个地方消耗了这些内存及相应时间。但此时编译好的golang程序对我们而言是黑盒,如果去分析具体的内存及时间使用情况?这个时候我们可以去了解和使用pprof来分析golang进程的内存使用。
yaohong
2021/12/16
1.1K0
golang pprof
golang定位内存泄露与cpu占用过高的方法与实战
现在使用golang的项目越来越多,但是当golang发生内存泄露或cpu占用过高时,怎么定位呢?其实很简单,按如下所述步骤操作即可:
shionyu
2018/08/30
17.5K0
golang定位内存泄露与cpu占用过高的方法与实战
听说你会内存分析?来,pprof一下
大家好,我是小❤,一个漂泊江湖多年的 985 非科班程序员,曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。
xin猿意码
2024/03/04
6290
听说你会内存分析?来,pprof一下
Go语言之性能分析工具pprof
pprof:是Go的性能分析工具,在程序运行过程中,可以记录程序的运行信息,可以是CPU使用情况、内存使用情况、goroutine运行情况等,Go语言已经将pprof 封装在包net/http/pprof中。
灰子学技术
2020/04/02
2.4K0
实战Go内存泄露
最近解决了我们项目中的一个内存泄露问题,事实再次证明pprof是一个好工具,但掌握好工具的正确用法,才能发挥好工具的威力,不然就算你手里有屠龙刀,也成不了天下第一,本文就是带你用pprof定位内存泄露问题。
大彬
2019/05/28
5.2K0
Go每日一库之90:gops
通常可以把Addr设置为要监听的IP,把ShutdownCleanup设置为ture,进程退出后,残留在ConfigDir目录的文件不再有用,最好清除掉。 ConfigDir示例:
luckpunk
2023/09/30
3730
从实例出发,深入理解pprof原理与应用
内存泄漏是指在计算机程序中,由于程序未能正确释放已经申请的内存空间,导致系统的可用内存持续减少,最终可能导致程序性能下降甚至崩溃的问题。
Michel_Rolle
2023/12/11
3K9
记一次golang内存泄露
最近在QA环境上验证功能时,发现机器特别卡,查看系统内存,发现可用(available)内存仅剩200多M,通过对进程耗用内存进行排序,发现有一个名为application-manager的容器服务的内存占用达到700多M,该服务使用Gin框架对外提供操作k8s资源的简单功能,解析客户端请求,并将结果返回给客户端。由于是测试环境,访问量极少,但内存一直只增不减,从最初的10M,一直增加到700多M,最终由于OOM而被重启(Pod)。
charlieroro
2021/06/02
1.5K0
Golang 大杀器之性能剖析 PProf
想要进行性能优化,首先瞩目在 Go 自身提供的工具链来作为分析依据,本文将带你学习、使用 Go 后花园,涉及如下:
前端教程
2018/10/25
2.4K0
Golang 大杀器之性能剖析 PProf
golang:快来抓住让我内存泄漏的“真凶”!
导语 | 有句话说得好:“golang10次内存泄漏,8次goroutine泄漏,1次真正内存泄漏”,那还有一次是什么呢?别急,下面就结合本次线上遇到的问题来讲一讲golang的内存泄漏和分析解决办法。 一、起——内存泄漏表现 在平常开发中golang的gc已经帮我们解决了很多问题了,甚至逐渐已经忘了有gc这种操作。但是在近期线上的一个trpc-go项目的表现实在让人匪夷所思,先让我们看看该患者的症状: 也是那么巧,每天晚上八点左右,服务的内存就开始暴涨,曲线骤降的地方都是手动重启服务才降下来的,内存
腾讯云开发者
2023/05/05
3.2K0
golang:快来抓住让我内存泄漏的“真凶”!
让你最快上手 go 的 pprof 性能分析大杀器
前言,发现一直没有记录过 pprof 分析的博客,其实在实际的业务场景中已经使用它很多次了,对于性能分析来说它真的是一大杀器,基本上有了它,80% 的性能问题都能被一目了然。每次出现性能问题,总是下面几个步骤,测试环境开 pprof,启动,流量重放,火焰图生成,一看,仔细分析一下,问题就浮于水面。
LinkinStar
2022/09/01
8670
让你最快上手 go 的 pprof 性能分析大杀器
Golang程序性能分析(一)pprof和go-torch
最近计划用三篇文章讲述一下Golang应用性能分析,本文是第一篇,先来介绍Go语言自带的性能分析库pprof怎么使用,后面两篇会讲解怎么用pprof对Echo或者Gin框架开发的应用进行性能分析以及如何使用pprof对gRPC 服务进行性能分析。
KevinYan
2020/11/26
1.2K1
自古以来,JSON序列化就是兵家必争之地
上文讲到使用ioutil.ReadAll读取大的Response Body,出现读取Body超时的问题。
有态度的马甲
2022/03/30
7500
自古以来,JSON序列化就是兵家必争之地
Golang pprof 性能问题分析优化和实战经验
Go 自带了一个 pprof 的性能优化和分析的工具,这个工具包括 cpuprof 、memprof ,并且还提供了 Lookup 功能用于获取堆状态信息、线程状态信息、 goroutine 状态信息等。官方的博客有一篇文章介绍用法:《Profiling Go Programs》[1]
Allen.Wu
2023/03/01
3K0
Golang pprof 性能问题分析优化和实战经验
go:如何定位内存cpu问题
此时,可以在web浏览器中输入http://localhost:6060/debug/pprof/,并点击进入 heap,查看信息。 重要的数据在下面:
超级大猪
2019/11/21
8590
Golang程序性能分析
程序性能分析我相信是每个程序员都会遇到的问题,比如说一个程序的CPU为什么占用这么高?有没有优化的空间?又比如程序出现了内存泄漏如何排查等等。如果是C++程序会借助于Google pprof c++ profile,java程序会依赖于jstack等工具,幸运的是Golang语言本身就集成了性能分析工具pprof包,可以有效的分析程序CPU,MEM,Metux等指标。其中还可以通过第三方图形应用来更加直观的显示每个调用关系和指标占用情况。
用户2937493
2019/09/11
2.1K0
Golang程序性能分析
【Go】优雅的读取http请求或响应的数据
从 http.Request.Body 或 http.Response.Body 中读取数据方法或许很多,标准库中大多数使用 ioutil.ReadAll 方法一次读取所有数据,如果是 json 格式的数据还可以使用 json.NewDecoder 从 io.Reader 创建一个解析器,假使使用 pprof 来分析程序总是会发现 bytes.makeSlice 分配了大量内存,且总是排行第一,今天就这个问题来说一下如何高效优雅的读取 http 中的数据。
thinkeridea
2019/11/04
4.3K0
【Go】优雅的读取http请求或响应的数据
相关推荐
生产环境Go程序内存泄露,用pprof如何快速定位
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验