作者:宁亮
//可使用go tool compile --help查看可用参数及含义
go build -gcflags="-m"? ?
比如 -N 禁用编译优化,-l 禁止内联,-m 打印编译优化策略(包括逃逸情况和函数是否内联,以及变量分配在堆或栈),-S 是打印汇编。
如果只在编译特定包时需要传递参数,格式应遵守“包名=参数列表”,如 go build -gcflags='log=-N -l' main.go
go build 用 -ldflags 给 go 链接器传入参数,实际是给 go tool link 的参数,可以用 go tool link --help 查看可用的参数。
常用 -X 来指定版本号等编译时才决定的参数值。例如代码中定义var buildVer string,然后在编译时用go build -ldflags "-X main.buildVer=1.0" 来赋值。注意 -X 只能给string类型变量赋值。
可以列出 go build 触发的所有命令,比如工具链、跨平台编译、传入外部编译器的 flags、链接器等,可使用 -x 来查看所有的触发。
使用 go run -race main.go 或 go build -race main.go 来进行竞争检测。
例如 GODEBUG=gctrace=1 go run main.go //跟踪打印垃圾回收器信息,Go 程序会每隔一段时间打印一些 gc 信息。
Go 语言内置了获取程序运行数据的工具,包括以下两个标准库
(1)runtime/pprof:采集工具型应用运行数据进行分析
(2)net/http/pprof:采集服务型应用运行时数据进行分析
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、1、2、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可以追踪程序
1、Go 语言提供了 race 检测(Go race detector)来进行竞争分析和发现。
2、go run -race main.go 是运行时检测,并不是编译时。使用 race 时存在明显的性能开销,因此尽量不要在生产环境中使用这个。
info goroutines //打印所有的goroutines
goroutine ${id} bt //打印一个goroutine的堆栈
iface //打印静态或者动态的接口类型
len //打印string,slices,map,channels 这四种类型的长度
cap //打印slices,channels 这两种类型的cap
dtype //强制转换接口到动态类型
扫码加好友拉你入技术交流群,加微暗号:思否
解决方法如下: 第一种 使用iframe,但是目前使用iframe的人已经越来越少了,而...
Redis 官方在 2020 年 5 月正式推出 6.0 版本,提供很多振奋人心的新特性,所以...
John Au-Yeung 来源:medium 译者:前端小智 有梦想,有干货,微信搜索 【大迁世...
注释1:上图整个大背景是这个网页的全部尺寸,中间的小框才是浏览器中的可见尺寸...
复制代码 代码如下: !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional...
content属性一般用于::before、::after伪元素中,用于呈现伪元素的内容。平时con...
先点赞再看,养成好习惯 前言 这两天在另一个社区看到了一个关于 Tomcat 的提问...
1.HTML5的内容类型 内容类型 描述 内嵌 向文档中添加其他类型的内容,例如audio...
简介: 企业上云多账号架构中,如何做到从上到下管理的同时,处理好员工的权限边...
data URI scheme 允许我们使用内联(inline-code)的方式在网页中包含数据,可以...