go pprof 的使用操作代码

目录
  • 背景
  • pprof 是什么
  • gin 框架使用 pprof
  • 火焰图
  • 总结

背景

最近合作开发一个项目,项目部署发现了才跑了没多久,就直接宕机了,查看服务器信息发现在某个时间端内存猛的暴涨了非常多,由于是合作开发的项目,我仔细的检查了自己的拿块代码,都没啥问题,另一个开发也说自己的代码没啥问题。

这没理没据的争论也不是个事,突然想起还有 pprof 这么个东西,正好能用上了。一顿操作下来,总算是找到了问题的根源。

pprof 是什么

pprofgo 中进行性能分析的工具,可以提供可视化数据查看。

pprof 的采样方式

  • runtime/pprof
  • net/http/pprof
  • test

这里举例采样内存信息。

package main
import (
	"os"
	"runtime/pprof"
)

func main() {
	var buf = make([][1024 * 1024]byte, 0)
	for i := 0; i < 100; i++ {
		buf = append(buf, [1024 * 1024]byte{})
	}
	f, err := os.OpenFile("heapProfile", os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.ModePerm)
	if err != nil {
		return
	}
	err = pprof.WriteHeapProfile(f)
	if err != nil {
		return
	}
	println("结束")
}

程序跑完之后会在本地生成 heapProfile 文件,命令行执行 go tool pprof heapProfile 可进入终端交互,可以输入 top 等命令查看:

这里可以输入 web 查看可视化界面,如果遇到 Could not execute dot; may need to install graphviz. 错误,需要自行安装,网上教程很多,本篇不提了。

顺带提一下 runtime.MemStats 结构体字段解释

Alloc uint64 //golang语言框架堆空间分配的字节数
TotalAlloc uint64 //从服务开始运行至今分配器为分配的堆空间总 和,只有增加,释放的时候不减少
Sys uint64 //服务现在系统使用的内存
Lookups uint64 //被runtime监视的指针数
Mallocs uint64 //服务分配内存对象的次数
Frees uint64 //服务回收内存对象的次数
HeapAlloc uint64 //服务分配的堆内存字节数
HeapSys uint64 //系统分配的作为运行栈的内存
HeapIdle uint64 //申请但是未分配的堆内存或者回收了的堆内存(空闲)字节数
HeapInuse uint64 //正在使用的堆内存字节数
HeapReleased uint64 //返回给OS的堆内存,类似C/C++中的free。
HeapObjects uint64 //堆内存块申请的量
StackInuse uint64 //正在使用的栈字节数
StackSys uint64 //系统分配的作为运行栈的内存
MSpanInuse uint64 //用于测试用的结构体使用的字节数
MSpanSys uint64 //系统为测试用的结构体分配的字节数
MCacheInuse uint64 //mcache结构体申请的字节数(不会被视为垃圾回收)
MCacheSys uint64 //操作系统申请的堆空间用于mcache的字节数
BuckHashSys uint64 //用于剖析桶散列表的堆空间
GCSys uint64 //垃圾回收标记元信息使用的内存
OtherSys uint64 //golang系统架构占用的额外空间
NextGC uint64 //垃圾回收器检视的内存大小
LastGC uint64 // 垃圾回收器最后一次执行时间。
PauseTotalNs uint64 // 垃圾回收或者其他信息收集导致服务暂停的次数。
PauseNs [256]uint64 //一个循环队列,记录最近垃圾回收系统中断的时间
PauseEnd [256]uint64 //一个循环队列,记录最近垃圾回收系统中断的时间开始点。
NumForcedGC uint32 //服务调用runtime.GC()强制使用垃圾回收的次数。
GCCPUFraction float64 //垃圾回收占用服务CPU工作的时间总和。如果有100个goroutine,垃圾回收的时间为1S,那么就占用了100S。
BySize //内存分配器使用情况

net/http/pprof

需要引入 net/http/pprof

package main
import (
	"net/http"
	_ "net/http/pprof"
)

func main() {
	_ = http.ListenAndServe("0.0.0.0:6060", nil)
}

然后访问服务地址 http://127.0.0.1:6060/debug/pprof 即可看到如下图所示的调试界面:

  • allocs:查看过去所有内存分配的样本。
  • block:查看导致阻塞同步的堆栈跟踪。
  • cmdline: 当前程序的命令行的完整调用路径。
  • goroutine:查看当前所有运行的 goroutines 堆栈跟踪。
  • heap:查看活动对象的内存分配情况。
  • mutex:查看导致互斥锁的竞争持有者的堆栈跟踪。
  • profile: 默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件。
  • threadcreate:查看创建新 OS 线程的堆栈跟踪。
  • trace:略,trace可以单独写一篇文章来介绍。

这里需要注意,如果需要对 blockmutex 的信息进行追踪,需要在代码中显式加上以下代码:

	runtime.SetBlockProfileRate(1) // 开启对阻塞操作的跟踪,block
	runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪,mutex

gin 框架使用 pprof

gingo 社区中使用较为广泛的一个 http 服务框架,其使用 pprof 进行性能分析,也有现成的轮子可以使用,引入 github.com/gin-contrib/pprof 即可,其实就是对于 net/http/pprof 的一个包装。

package main
import (
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
)

func main() {
	engine := gin.Default()
	pprof.Register(engine)
}

test

 	-bench=.
         进行性能测试,“.”是正则匹配,匹配了所有的测试函数

    -benchmem
        打印出申请内存的次数。一般用于简单的性能测试,不会导出数据文件。

    -blockprofile block.out
        将协程的阻塞数据写入特定的文件(block.out)。如果-c,则写成二进制文件。

    -cpuprofile cpu.out
        将协程的CPU使用数据写入特定的文件(cpu.out)。如果-c,则写成二进制文件。

    -memprofile mem.out
        将协程的内存申请数据写入特定的文件(mem.out)。如果-c,则写成二进制文件。

    -mutexprofile mutex.out
        将协程的互斥数据写入特定的文件(mutex.out)。如果-c,则写成二进制文件。

    -trace trace.out
        将执行调用链写入特定文件(trace.out)。

test 导出的数据也需要通过 go tool pprof 来分析。

火焰图

安装

go get -u github.com/google/pprof

启动

pprof -http=:8080 heapProfile

访问 http://localhost:8080 可以得到下图:

每个块都是可点击的,可以进行深度分析。

总结

pprofgo 中做性能分析的很强大的一个工具,支持内存,cpu,锁,goroutine 等数据采集,本篇主要是做个简单介绍,真正进行分析的时候,需要耐心了解各种图,数据展示的含义,一般来说还是比较好理解的。

pprof 性能分析是个很大的知识点,本篇仅做了简单的介绍,最好自己深入理解学习一下。

参考

golang pprof 实战-CPU,heap,alloc,goroutine,mutex,block

Go 语言编程之旅-pprof篇

实用go pprof使用指南

到此这篇关于go pprof 的使用的文章就介绍到这了,更多相关go pprof 使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang利用pprof与go-torch如何做性能分析

    前言 软件开发过程中,项目上线并不是终点.上线后,还要对程序的取样分析运行情况,并重构现有的功能,让程序执行更高效更稳写. golang的工具包内自带pprof功能,使找出程序中占内存和CPU较多的部分功能方便了不少.加上uber的火焰图,可视化显示,让我们在分析程序时更简单明了. pprof有两个包用来分析程序一个是net/http/pprof另一个是runtime/pprof,net/http/pprof只是对runtime/pprof包进行封装并用http暴露出来,如下图源码所示: 使用n

  • go性能分析工具pprof的用途及使用详解

    目录 pprof的用途 利用runtime/pprof包实现cpu分析的步骤 利用runtime/pprof包实现内存分析的步骤: 利用net/http/pprof包进行性能分析 总结 pprof的用途 CPU Profiling:CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗CPU 周期时花费时间的位置 Memory Profiling:内存分析,在应用程序进行堆分配时记录堆栈跟踪,用于监视当前和历史内存使用情况,以及检查内存泄漏 Bl

  • Go pprof内存指标含义备忘录及案例分析

    最近组内一些Go服务碰到内存相关的问题,所以今天抽时间看了下Go pprof内存指标的含义,为后续查问题做准备. 内容主要来自于Go代码中对这些字段的注释,加自己的理解.理解不对的地方欢迎指正. // https://github.com/golang/go/blob/master/src/runtime/mstats.go#L150 // 总共从OS申请的字节数 // 是下面各种XxxSys指标的总和.包含运行时的heap.stack和其他内部数据结构的总和. // 它是虚拟内存空间.不一定全

  • Golang pprof性能测试与分析讲解

    目录 一.性能分析类型 1.CPU性能分析 2.内存性能分析 3.阻塞性能分析 二.cpu性能分析 1.生成pporf 2.分析数据 三.内存性能分析 四.benchmark 生成 profile 一.性能分析类型 1.CPU性能分析 CPU性能分析是最常见的性能分析类型.启动CPU分析时,运行时每隔10ms中断一次,采集正在运行协程的堆栈信息. 程序运行结束后,可以根据收集的数据,找到最热代码路径. 一个函数在分析阶段出现的次数越多,则该函数的代码路径(code path)花费的时间占总运行时

  • Go 库性能分析工具pprof

    目录 场景 pprof 生成 profile 文件 CPU 性能分析 内存性能分析 分析 profile 文件 && 优化代码 go tool pprof top 命令 list 命令 总结 场景 我们一般没必要过度优化 Go 程序性能.但是真正需要时,Go 提供的 pprof 工具能帮我们快速定位到问题.比如,我们团队之前有一个服务,在本地和测试环境没问题,一到灰度环境,就报 cpu 负载过高,后经排查,发现某处代码死循环了.我把代码简化成如下: // 处理某些业务,真实的代码中这个死循

  • Go程序性能优化及pprof使用方法详解

    Go 程序的性能优化及 pprof 的使用 程序的性能优化无非就是对程序占用资源的优化.对于服务器而言,最重要的两项资源莫过于 CPU 和内存.性能优化,就是在对于不影响程序数据处理能力的情况下,我们通常要求程序的 CPU 的内存占用尽量低.反过来说,也就是当程序 CPU 和内存占用不变的情况下,尽量地提高程序的数据处理能力或者说是吞吐量. Go 的原生工具链中提供了非常多丰富的工具供开发者使用,其中包括 pprof. 对于 pprof 的使用要分成下面两部分来说. Web 程序使用 pprof

  • MongoDB快速入门笔记(八)之MongoDB的java驱动操作代码讲解

    MongoDB的Java驱动是线程安全的,对于一般的应用,只要一个Mongo实例即可,Mongo有个内置的连接池(池大小默认为10个). 下面代码给大家介绍MongoDB的java驱动操作,具体代码如下所示: import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.bson.Document; import com.mongodb.MongoClient; impo

  • hibernate增删改查操作代码

    Hibernate对数据删除操作 删除User表中个一条数据,是需要更具User表的主键id值来删除的.首先根据id值向数据库中查询出来对应的对象.可以采用两种方式一是session的get方法,一个是session的load方法. Session的Get方法:调用这个方法会返回一个Object对象.然后我们对其强制转换.Useruser = (User)session.get(User.class," 402881e5441c035e01441c0360510003"); 当我们传递

  • 使用vue与jquery实时监听用户输入状态的操作代码

    实现效果:input未输入值,按钮禁用 jquery操作代码: html <input type="text" name="" placeholder="请输入用户名" id="userName" > <button class="disabled" id="login">登录</button> css .disabled { pointer-even

  • Java远程共享目录的操作代码

    一.前言 根据客户反馈,在进行文件下载的时候,新增远程共享目录,下载对应的文件到远程共享目录,采用常用的IO操作模式,提示下载成功,但是客户去远程共享目录查看对应的下载文件,反馈说没有找到对应的文件.要求系统需要支持上传远程共享目录,为什么有一个这样的需求?由于下载的文件涉及到了支付文件,里面的金额不允许进行修改,如果放在本地路径有可能会不会出现人为的修改,一般涉及到钱的问题,客户都是比较谨慎的,刚好没有接触过操作远程共享目录的,就google了一下看有没有对应的操作说明,下面简单总结一下. 二

  • 关于jQuery里prev()的简单操作代码

    prev() 函数被用来匹配元素集的前一个兄弟元素,仅仅只有前一个兄弟元素被选择,其子元素将被忽略.这里给大家介绍jQuery里prev()的简单操作,具体内容如下: 一个朋友提了个需求给我:点击按钮删除input,如果input剩一个,点击按钮全部消失. 很简单的操作,但是你如果不知道jquery里有prev()这个方法,可能你会走很多弯路. 代码: html <div> <input type="text" placeholder="用户名"&

  • JS switch判断 三目运算 while 及 属性操作代码

    三 目运算:如var a = 10: var b= 12: c = a>b ?a:b; 若成立执行a否则执行b var isHide = true; 若用if判断语句如下 if(isHide) { box.style.display = "block"; } else { box.style.display = "none"; } 三目运算替代if box.style.display = isHide?"block":"none&

  • Mybatis批量修改的操作代码

    1.修改的字段值都是一样的,id不同 <update id="batchUpdate" parameterType="String"> update cbp_order set status=1 where id in <foreach item="id" collection="array" open="(" separator="," close=")&q

  • java编程无向图结构的存储及DFS操作代码详解

    图的概念 图是算法中是树的拓展,树是从上向下的数据结构,结点都有一个父结点(根结点除外),从上向下排列.而图没有了父子结点的概念,图中的结点都是平等关系,结果更加复杂. 无向图                                                       有向图 图G=(V,E),其中V代表顶点Vertex,E代表边edge,一条边就是一个定点对(u,v),其中(u,v)∈V. 这两天遇到一个关于图的算法,在网上找了很久没有找到java版的关于数据结构中图的存储及其

  • Hibernate中Session增删改查操作代码详解

    把三状态转换图放在这,方便分析方法的作用: 1.Session的save()方法 Session是Hibernate所有接口中最重要的接口,提供了对数据保存,更新,查询和删除的方法. Session的save()方法可以使临时态或游离态转换为持久态.例如,保存一个Customer对象: SessionFactory sessionFactory; Configuration configuration = new Configuration().configure(); sessionFacto

  • Jedis对redis的五大类型操作代码详解

    本篇主要阐述Jedis对redis的五大类型的操作:字符串.列表.散列.集合.有序集合. JedisUtil 这里的测试用例采用junit4进行运行,准备代码如下: private static final String ipAddr = "10.10.195.112"; private static final int port = 6379; private static Jedis jedis= null; @BeforeClass public static void init

随机推荐