做者:宁亮html
//可以使用go tool compile --help查看可用参数及含义 go build -gcflags="-m"
好比 -N 禁用编译优化,-l 禁止内联,-m 打印编译优化策略(包括逃逸状况和函数是否内联,以及变量分配在堆或栈),-S 是打印汇编。node
若是只在编译特定包时须要传递参数,格式应遵照“包名=参数列表”,如 go build -gcflags='log=-N -l' main.gogit
go build 用 -ldflags 给 go 连接器传入参数,实际是给 go tool link 的参数,能够用 go tool link --help 查看可用的参数。github
经常使用 -X 来指定版本号等编译时才决定的参数值。例如代码中定义var buildVer string,而后在编译时用go build -ldflags "-X main.buildVer=1.0" 来赋值。注意 -X 只能给string类型变量赋值。golang
能够列出 go build 触发的全部命令,好比工具链、跨平台编译、传入外部编译器的 flags、连接器等,可以使用 -x 来查看全部的触发。web
使用 go run -race main.go 或 go build -race main.go 来进行竞争检测。json
例如 GODEBUG=gctrace=1 go run main.go //跟踪打印垃圾回收器信息,Go 程序会每隔一段时间打印一些 gc 信息。api
Go 语言内置了获取程序运行数据的工具,包括如下两个标准库浏览器
(1)runtime/pprof:采集工具型应用运行数据进行分析
(2)net/http/pprof:采集服务型应用运行时数据进行分析sass
f, err := os.Create(*cpuprofile) ... pprof.StartCPUProfile(f) defer pprof.StopCPUProfile()
f, err := os.Create(*memprofile) pprof.WriteHeapProfile(f) f.Close()
package main import ( "log" "net/http" _ "net/http/pprof" ) func main() { //... do something log.Println(http.ListenAndServe("localhost:8090", nil)) }
package main import ( "github.com/gin-contrib/pprof" "github.com/gin-gonic/gin" ) func main() { app := gin.Default() pprof.Register(app) app.Run(":8090") }
如在本机测试服务上启用 pprof,可使用 http://127.0.0.1:8090/debug/p... http 服务:
/debug/pprof/ Types of profiles available: Count Profile 3 allocs 0 block //goroutine的阻塞信息 0 cmdline 4 goroutine //此项可排查是否建立了大量的 goroutine 3 heap //堆内存的分配信息 0 mutex //锁的信息 0 profile 7 threadcreate //线程信息 0 trace full goroutine stack dump //此项可排查是否有 goroutine 运行时间过长
pprof开启后,每隔一段时间(默认10ms)就会收集当前的堆栈信息,获取各个函数占用的CPU以及内存资源,而后经过对这些采样数据进行分析,造成一个性能分析报告。
如在 Mac 上经过 brew 安装 graphviz,能够执行如下命令 brew install graphviz
能够先把信息 dump 到本地文件,而后用 go tool 去分析。
一个能够实时查看 go 程序内存、CPU、GC、协程等变化状况的可视化工具。启用方式跟 pprof 相似,都是先 import 引入,而后开启端口监听便可。
package main import ( _ "github.com/mkevac/debugcharts" "log" "net/http" ) func main() { //... do something log.Println(http.ListenAndServe("localhost:8090", nil)) }
而后在浏览器中打开查看:http://127.0.0.1:8090/debug/c...
prometheus 是 grafana 的插件,支持 go 监控的可视化。
启用方式也是先引入包:
import ( "github.com/prometheus/client_golang/prometheus/promhttp" )
而后增长路由:
//prometheus http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":8090", nil)
最后,经过访问 http://127.0.0.1:8090/metrics 查看采集到的指标数据。
注:也能够经过一个端口同时开启 pprof + charts + prometheus。
addr2line api asm buildid cgo compile:代码汇编 cover:生成代码覆盖率 dist doc fix link nm:查看符号表(等同于系统 nm 命令) objdump:反汇编工具,分析二进制文件(等同于系统 objdump 命令) oldlink pack pprof:性能和指标分析工具 test2json trace:采样一段时间,指标跟踪分析工具 vet
在断点的时候,若是不知道断点的函数符号,能够用这个命令进行查询(命令处理的是二进制程序文件)。
go tool nm ./main
输出的第一列是地址,第二列是类型,第三列是符号。
115aa00 T bufio.(*ReadWriter).Available
115aa20 T bufio.(*ReadWriter).Discard
115aa60 T bufio.(*ReadWriter).Flush
115aa80 T bufio.(*ReadWriter).Peek
go tool compile -N -l -S main.go
go tool objdump main.o go tool objdump -s DoFunc main.o //反汇编具体函数
go tool pprof http://localhost:8090/debug/p... 分析heap,进入命令行模式,输入 web 便可以web方式打开(前提是安装了graphviz)。
或者继续输入命令:
在命令行输入top默认查看程序中占用内存前10位的函数,在命令行输入top 3能够查看程序中占用内存前3位的函数。一样,若是采集的是cpu使用top命令能够看占用cpu的函数
(1)输入top后显示的最后一列为函数名称,其余各项内容意义以下:
flat:当前函数占用CPU的耗时
flat%:当前函数占用CPU的耗时百分比
sum%:函数占用CPU的累积耗时百分比
cum:当前函数+调用的子函数 占用CPU总耗时
cum%:当前函数+调用的子函数 占用CPU总耗时百分比
(2)能够在命令行输入 list+函数名 命令查看具体的函数分析
(3)能够在命令行输入 pdf 生成可视化的pdf文件
(4)能够在命令行输入 help 提供全部pprof支持的命令说明
(1)go tool pprof -http=:1234 http://localhost:8090/debug/p... 会直接以web方式打开。或者:http://localhost:1234/ui/ 也能够直接打开,从中能够直接筛选查看火焰图(Flame Graph)。-http 表示使用交互式web接口查看获取的性能信息,指定可用的端口便可。debug/pprof/须要查看的指标(allocs,block,goroutine,heap等)。火焰图从上往下是方法的调用栈,长度表明使用的cpu时长。
go tool pprof -http=:1234 http://localhost:8090/debug/pprof/goroutine?second=10 go tool pprof --seconds 10 http://localhost:8090/debug/pprof/goroutine
若是应用比较复杂,生成的调用图特别大,看起来很乱,有两个办法能够优化:
(1)使用 web [funcName] 的方式,只打印和某个函数相关的内容。
(2)运行 go tool pprof 命令时加上 --nodefration 参数,能够忽略内存使用较少的函数,好比--nodefration=0.05表示若是调用的子函数使用的 CPU、memory 不超过 5%,就忽略它,不要显示在图片中。
go test . //直接在本目录中运行go test go test -run=TestPutAndGetKeyValue //指定运行函数 go test -v //提供详细的测试输出,打印测试名称、状态(经过或者失败)、耗时、测试用例的日志等 go test -race //测试时支持对竞争进行检测和报告 go test -coverprofile=c.out && go tool cover -html=c.out //输出一个覆盖信息结果并可在浏览器上可视化观看
加一个 -coverprofile 的参数,声明在跑单测的时候,记录代码覆盖率。例如 go test -coverprofile=coverage.out
使用 go tool cover 命令分析,能够得出覆盖率报告 go tool cover -func=coverage.out
delve 当前是最友好的 golang 调试程序,ide 调试其实也是调用 dlv 而已,好比 goland使用的调试。
安装dlv:go get -u github.com/go-delve/delve/cmd/dlv
检查安装版本信息:dlv version
把程序加载进 Delve 调试器的两种方式(事先须要有go.mod)
dlv debug
(1)执行 dlv debug 进入命令行模式,此时同目录下会自动生成一个 __debug_bin 文件。这个文件是由源码编译生成的,并会自动加载进调试器。
(2)Delve 指望的是从单个程序或项目中构建出单个二进制文件,若是目录中有多个源文件且每一个文件都有本身的主函数, Delve 则可能抛出错误。此种状况下应该使用下面第二种方式,加载二进制文件进行调试。
dlv exec ./main
(1)使用 dlv exec 命令将二进制文件加载进调试器。
(2)在命令行模式下输入 help 查看可用命令。
(3)其常使用的一些命令:
b main.main //在 main 函数处设置断点,等同于 break main.main b func.go:5 //使用 文件名:行号 的格式来设置断点,也能够直接用行号设置断点 bp //查看设置的断点,等同于 breakpoints clear [断点标号如2] //清除单个断点 clearall //清除全部断点 on //设置一段命令,当断点命中的时候 c //继续运行程序,运行到断点处停止,等同于 continue n //单步调试下一行源码,等同于 next。默认状况下,Delve不会更深刻地调试函数调用。 s //单步调试下一个函数,等同于 step step-instruction //单步调试某个汇编指令 stack //打印当前堆栈的内容信息,能够看到0、一、二、3...等栈位置的函数 frame 0 //实现帧之间的跳转,可使用 stack 输出的位置序号 args //打印出命令行传给函数的参数 disassemble //查看编译器生成的汇编语言指令 stepout //跳回到函数被调用的地方 print [var_name] //打印变量的值 whatis [var_name] //打印变量的类型 locals //打印函数内的全部局部变量 regs //打印寄存器的信息 x //等同于examinemem,这个是解析内存用的,和 gdb 的 x 命令同样 set //set赋值 vars //打印全局变量(包变量) whatis //打印类型信息 r //从新启动并调试执行程序,等同于restart call //整个程序执行 quit //退出调试器
协程相关
goroutine (alias: gr) //打印某个特定协程的信息 goroutines (alias: grs) //列举全部的协程 goroutines -t //展开全部协程详细信息 thread (alias: tr) //切换到某个线程 threads //打印全部的线程信息
栈相关
deferred //在 defer 函数上下文里执行命令 down //上堆栈 frame //跳到某个具体的堆栈 stack (alias: bt) //打印堆栈信息 up //下堆栈
其余命令
config //配置变动 disassemble (alias: disass) //反汇编 funcs //打印全部函数符号 libraries //打印全部加载的动态库 list (alias: ls | l) //显示源码 source //加载命令 sources //打印源码 types //打印全部类型信息
(4)dlv的其它命令
dlv debug:使用dlv debug能够在main函数文件所在目录直接对main函数进行调试,也能够在根目录以指定包路径的方式对main函数进行调试 dlv exec:使用dlv exec能够对编译好的二进制进行调试 dlv test:使用dlv test能够对test包进行调试 dlv attach:使用dlv attach能够附加到一个已在运行的进程进行调试 dlv connect:使用dlv connect能够链接到调试服务器进行调试 dlv trace:使用dlv trace能够追踪程序
一、Go 语言提供了 race 检测(Go race detector)来进行竞争分析和发现。
二、go run -race main.go 是运行时检测,并非编译时。使用 race 时存在明显的性能开销,所以尽可能不要在生产环境中使用这个。
info goroutines //打印全部的goroutines goroutine ${id} bt //打印一个goroutine的堆栈 iface //打印静态或者动态的接口类型
len //打印string,slices,map,channels 这四种类型的长度 cap //打印slices,channels 这两种类型的cap dtype //强制转换接口到动态类型