前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang定位内存泄露与cpu占用过高的方法与实战

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

原创
作者头像
shionyu
发布2018-08-30 14:52:40
16.8K0
发布2018-08-30 14:52:40
举报
文章被收录于专栏:后台技术后台技术

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

简明步骤:

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

代码如下:

代码语言:txt
复制
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状态

代码语言:txt
复制
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测量,结果如下:

代码语言:txt
复制
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占用过高的方法也是一样的,就不展开了

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档