golang定位内存泄露与cpu占用过高的方法与实战

现在使用golang的项目越来越多,但是当golang发生内存泄露或cpu占用过高时,怎么定位呢?其实很简单,按如下所述步骤操作即可:

简明步骤:

1、import这个pprof包,然后开启一个端口来监听http请求,注意设置handle为nil。

代码如下:

import _ "net/http/pprof"
go func() {
   mux := http.NewServeMux()
   mux.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) {
      num := strconv.FormatInt(int64(runtime.NumGoroutine()), 10)
      w.Write([]byte(num))
   })
   http.ListenAndServe("127.0.0.1:6061", mux)
   http.ListenAndServe("127.0.0.1:6060", nil)
}()

解释下代码:开启6061端口可以查看golang当前的routine数,查看是否是routine泄露, 开启6060端口可以查看pprof相关信息

2、使用go命令调用pprof工具来查看内存或cpu状态

go tool pprof http://localhost:6060/debug/pprof/heap
go tool pprof http://localhost:6060/debug/pprof/profile

可以看到如下简单明了的信息,cum是cumulative,意思就是累积量,即累计使用了这么4g左右的内存,cum%就是占所有使用的百分比。根据这些信息,可以看到相应的代码行数,就能快速定位问题了。

=============== 实践:定位内存泄露 =================

问题与现象:线上的程序在部署一周后,使用内存上升了几倍,没有释放的迹象

解决此问题的思路:

1、review代码,看下是否是代码什么地方没有释放。但由于期间更改的代码很多,所以review代码的效率很低,解决问题的速度不够快。(此方法对于代码量修改量小而言,效率是比较高的)

2、使用工具来查看golang的内存状况,从占用内存有异常的相关代码行开始查起。(此方法相当于发烧了用体温计测,测了就知道问题出哪儿了,不过要借助工具)

用方法2测量,结果如下:

go tool pprof http://localhost:6060/debug/pprof/heap
(pprof) top20
Showing nodes accounting for 8547.30MB, 99.65% of 8577.40MB total
Dropped 30 nodes (cum <= 42.89MB)
      flat  flat%   sum%        cum   cum%
 4364.09MB 50.88% 50.88%  4364.09MB 50.88%  0000000000769fba /vreader.(*tClassicVideoReader).Read 
 3634.66MB 42.37% 93.25%  3634.66MB 42.37%  00000000005485fc bytes.makeSlice /usr/local/go/src/bytes/buffer.go:230
  340.03MB  3.96% 97.22%   340.03MB  3.96%  00000000004892a9 time.NewTimer /usr/local/go/src/time/sleep.go:86
  208.52MB  2.43% 99.65%   208.52MB  2.43%  00000000004892db time.NewTimer /usr/local/go/src/time/sleep.go:89
         0     0% 99.65%  3634.66MB 42.37%  0000000000547fb0 bytes.(*Buffer).grow /usr/local/go/src/bytes/buffer.go:144
         0     0% 99.65%  3629.34MB 42.31%  0000000000548159 bytes.(*Buffer).Grow /usr/local/go/src/bytes/buffer.go:163
         0     0% 99.65%  3629.34MB 42.31%  00000000005aca42 io/ioutil.readAll /usr/local/go/src/io/ioutil/ioutil.go:34
         0     0% 99.65%  3629.34MB 42.31%  00000000005acc54 io/ioutil.ReadFile /usr/local/go/src/io/ioutil/ioutil.go:73
         0     0% 99.65%  4364.09MB 50.88%  000000000076ab94 service/vreader.(*tMVSVideoReader).Read 
         0     0% 99.65%   548.54MB  6.40%  00000000007c4ad1 service.(*TFixedPool).inner_deal_pakeage 
         0     0% 99.65%   548.54MB  6.40%  00000000007c5087 service.inner_worker_send_recv 
         0     0% 99.65%   548.54MB  6.40%  00000000007c6a27 service.inner_worker_send_recv_with_timeout 
         0     0% 99.65%  3629.34MB 42.31%  00000000007c9c19 service.update_worker_face_feature 
         0     0% 99.65%   546.54MB  6.37%  00000000007ce9af service.(*TFixedPool).add_worker.func1 
         0     0% 99.65%  4364.09MB 50.88%  00000000007f3e38 apps/huaruncheng.hrcAiRoutineOneTry 

分析下:

1、占用内存4G左右的classic_reader看了代码,确认是缓存视频用到的内存,正常现象。

2、bytes.makeSlice占用了3G内存,看了代码发现是读文件同步特征值时创建buf产生的内存,正常现象。

3、time.NewTimer占用500M,根据关联查代码,计时器不应该用这么多内存,这里是有异常的。

走读了这部分涉及计时器的代码后发现是因为有个计时器在某些场景下设置了很大的触发时间(有的场景需要比较大的触发时间),但是在正确回包后又没有及时stop掉,所以就泄露了

定位cpu占用过高的方法也是一样的,就不展开了

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

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

发表于

后台技术

2 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android开发经验

让你的App有声音

11920
来自专栏张善友的专栏

K2 blackpearl 中的业务规则(Rules)

在K2流程系统中,流程中的任何一个执行节点(一个节点可以包含多个事件)都可能包含客户端事件,服务器端事件,以及子流程(IPC,Inter Process Com...

20570
来自专栏北京马哥教育

Nginx listen reuseport参数带来的性能提升

NGINX发布的1.9.1版本引入了一个新的特性:允许使用SO_REUSEPORT套接字选项,该选项在许多操作系统的新版本中是可用的,包括Bsd和Linux(内...

89790
来自专栏北京马哥教育

Linux基础之终端、控制台、tty、pty等概念简介

基本概念: 1>tty(终端设备的统称): tty一词源于teletypes,或者teletypewriters,原来指的是电传打字机,是通过串行线用打印机键盘...

38580
来自专栏Golang语言社区

[Go语言]一种用于网游服务器的支持多路复用的网络协议处理框架

简介: 本文描述了使用Go语言实现的、适应于Go语言并发模型的一种支持多路复用的网络协议处理框架,并提供了框架的代码实现。作者将这种框架用于网络游戏服务器中的协...

386100
来自专栏后端技术探索

后端线上服务监控与报警方案

一个功能上线后,其实研发心里根本没底儿,不知道这个功能上线以后是不是真的没问题;有经验一些老同学还知道直接登录线上机器去tail -f php.error.lo...

32920
来自专栏java学习

Java每日一题_关于redirect和forward

(不定项选择题) 下面有关forward和redirect的描述,正确的是() ?

10510
来自专栏linux驱动个人学习

CPUFreq驱动

CPUFreq子系统位于 drivers/cpufreq目录下,负责进行运行过程中CPU频率和电压的动态调整,即DvFS( Dynamic Voltage Fr...

16130
来自专栏Golang语言社区

[Go语言]一种用于网游服务器的支持多路复用的网络协议处理框架

简介: 本文描述了使用Go语言实现的、适应于Go语言并发模型的一种支持多路复用的网络协议处理框架,并提供了框架的代码实现。作者将这种框架用于网络游戏服务器中的协...

34360
来自专栏java系列博客

编译windows版的openJDK攻略

2.2K30

扫码关注云+社区

领取腾讯云代金券