做者:寧亮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 //強制轉換接口到動態類型