相信很多人都聽過“雷神 3”關(guān)于性能優(yōu)化的故事兽间。在一個(gè) 3D 游戲引擎的源碼里,John Carmack 將 1/sqrt(x)
這個(gè)函數(shù)的執(zhí)行效率優(yōu)化到了極致价匠。
一般我們使用二分法当纱,或者牛頓迭代法計(jì)算一個(gè)浮點(diǎn)數(shù)的平方根。但在這個(gè)函數(shù)里踩窖,作者使用了一個(gè)“魔數(shù)”坡氯,根本沒有迭代,兩步就直接算出了平方根洋腮。令人嘆為觀止箫柳!
因?yàn)樗亲畹讓拥暮瘮?shù),而游戲里涉及到大量的這種運(yùn)算啥供,使得在運(yùn)算資源極其緊張的 DOS 時(shí)代悯恍,游戲也可以流暢地運(yùn)行。這就是性能優(yōu)化的魅力伙狐!
工作中涮毫,當(dāng)業(yè)務(wù)量比較小的時(shí)候,用的機(jī)器也少贷屎,體會(huì)不到性能優(yōu)化帶來的收益罢防。而當(dāng)一個(gè)業(yè)務(wù)使用了幾千臺(tái)機(jī)器的時(shí)候,性能優(yōu)化 20%豫尽,那就能省下幾百臺(tái)機(jī)器篙梢,一年能省幾百萬。省下來的這些錢美旧,給員工發(fā)年終獎(jiǎng)渤滞,那得多 Happy!
一般而言榴嗅,性能分析可以從三個(gè)層次來考慮:應(yīng)用層妄呕、系統(tǒng)層、代碼層嗽测。
應(yīng)用層主要是梳理業(yè)務(wù)方的使用方式绪励,讓他們更合理地使用,在滿足使用方需求的前提下唠粥,減少無意義的調(diào)用疏魏;系統(tǒng)層關(guān)注服務(wù)的架構(gòu),例如增加一層緩存晤愧;代碼層則關(guān)心函數(shù)的執(zhí)行效率大莫,例如使用效率更高的開方算法等。
做任何事官份,都要講究方法只厘。在很多情況下烙丛,迅速把事情最關(guān)鍵的部分完成,就能拿到絕大部分的收益了羔味。其他的一些邊邊角角河咽,可以慢慢地縫合。一上來就想完成 100%赋元,往往會(huì)陷入付出了巨大的努力忘蟹,卻收獲寥寥的境地。
性能優(yōu)化這件事也一樣们陆,識別出性能瓶頸寒瓦,會(huì)讓我們付出最小的努力,而得到最大的回報(bào)坪仇。
Go 語言里,pprof 就是這樣一個(gè)工具垃你,幫助我們快速找到性能瓶頸椅文,進(jìn)而進(jìn)行有針對性地優(yōu)化。
什么是 pprof
代碼上線前惜颇,我們通過壓測可以獲知系統(tǒng)的性能皆刺,例如每秒能處理的請求數(shù),平均響應(yīng)時(shí)間凌摄,錯(cuò)誤率等指標(biāo)羡蛾。這樣,我們對自己服務(wù)的性能算是有個(gè)底锨亏。
但是壓測是線下的模擬流量痴怨,如果到了線上呢?會(huì)遇到高并發(fā)器予、大流量浪藻,不靠譜的上下游细燎,突發(fā)的尖峰流量等等場景旁舰,這些都是不可預(yù)知的秕豫。
線上突然大量報(bào)警危纫,接口超時(shí)渔欢,錯(cuò)誤數(shù)增加橄唬,除了看日志赎瞎、監(jiān)控揍很,就是用性能分析工具分析程序的性能雷则,找到瓶頸辆雾。當(dāng)然,一般這種情形不會(huì)讓你有機(jī)會(huì)去分析巧婶,降級乾颁、限流涂乌、回滾才是首先要做的,要先止損嘛英岭⊥搴校回歸正常之后,通過線上流量回放诅妹,或者壓測等手段罚勾,制造性能問題,再通過工具來分析系統(tǒng)的瓶頸吭狡。
一般而言尖殃,性能分析主要關(guān)注 CPU、內(nèi)存划煮、磁盤 IO送丰、網(wǎng)絡(luò)這些指標(biāo)。
Profiling
是指在程序執(zhí)行過程中弛秋,收集能夠反映程序執(zhí)行狀態(tài)的數(shù)據(jù)器躏。在軟件工程中,性能分析(performance analysis蟹略,也稱為 profiling)登失,是以收集程序運(yùn)行時(shí)信息為手段研究程序行為的分析方法,是一種動(dòng)態(tài)程序分析的方法挖炬。
Go 語言自帶的 pprof 庫就可以分析程序的運(yùn)行情況揽浙,并且提供可視化的功能。它包含兩個(gè)相關(guān)的庫:
runtime/pprof
對于只跑一次的程序意敛,例如每天只跑一次的離線預(yù)處理程序馅巷,調(diào)用 pprof 包提供的函數(shù),手動(dòng)開啟性能數(shù)據(jù)采集空闲。net/http/pprof
對于在線服務(wù)令杈,對于一個(gè) HTTP Server,訪問 pprof 提供的 HTTP 接口碴倾,獲得性能數(shù)據(jù)逗噩。當(dāng)然,實(shí)際上這里底層也是調(diào)用的 runtime/pprof 提供的函數(shù)跌榔,封裝成接口對外提供網(wǎng)絡(luò)訪問异雁。
pprof 的作用
pprof
是 Go 語言中分析程序運(yùn)行性能的工具,它能提供各種性能數(shù)據(jù):
allocs
和 heap
采樣的信息一致僧须,不過前者是所有對象的內(nèi)存分配纲刀,而 heap 則是活躍對象的內(nèi)存分配。
The difference between the two is the way the pprof tool reads there at start time. Allocs profile will start pprof in a mode which displays the total number of bytes allocated since the program began (including garbage-collected bytes).
上圖來自參考資料【wolfogre】的一篇 pprof 實(shí)戰(zhàn)的文章担平,提供了一個(gè)樣例程序示绊,通過 pprof 來排查锭部、分析、解決性能問題面褐,非常精彩拌禾。
- 當(dāng) CPU 性能分析啟用后,Go runtime 會(huì)每 10ms 就暫停一下展哭,記錄當(dāng)前運(yùn)行的 goroutine 的調(diào)用堆棧及相關(guān)數(shù)據(jù)湃窍。當(dāng)性能分析數(shù)據(jù)保存到硬盤后,我們就可以分析代碼中的熱點(diǎn)了匪傍。
- 內(nèi)存性能分析則是在堆(Heap)分配的時(shí)候您市,記錄一下調(diào)用堆棧。默認(rèn)情況下役衡,是每 1000 次分配茵休,取樣一次,這個(gè)數(shù)值可以改變手蝎。棧(Stack)分配 由于會(huì)隨時(shí)釋放泽篮,因此不會(huì)被內(nèi)存分析所記錄。由于內(nèi)存分析是取樣方式柑船,并且也因?yàn)槠溆涗浀氖欠峙鋬?nèi)存,而不是使用內(nèi)存泼各。因此使用內(nèi)存性能分析工具來準(zhǔn)確判斷程序具體的內(nèi)存使用是比較困難的鞍时。
- 阻塞分析是一個(gè)很獨(dú)特的分析,它有點(diǎn)兒類似于 CPU 性能分析扣蜻,但是它所記錄的是 goroutine 等待資源所花的時(shí)間逆巍。阻塞分析對分析程序并發(fā)瓶頸非常有幫助,阻塞性能分析可以顯示出什么時(shí)候出現(xiàn)了大批的 goroutine 被阻塞了莽使。阻塞性能分析是特殊的分析工具锐极,在排除 CPU 和內(nèi)存瓶頸前,不應(yīng)該用它來分析芳肌。
pprof 如何使用
我們可以通過
報(bào)告生成
灵再、Web 可視化界面
、交互式終端
三種方式來使用pprof
亿笤。
—— 煎魚《Golang 大殺器之性能剖析 PProf》
runtime/pprof
拿 CPU profiling 舉例翎迁,增加兩行代碼,調(diào)用 pprof.StartCPUProfile
啟動(dòng) cpu profiling净薛,調(diào)用 pprof.StopCPUProfile()
將數(shù)據(jù)刷到文件里:
import "runtime/pprof"
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
// …………
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// …………
}
net/http/pprof
啟動(dòng)一個(gè)端口(和正常提供業(yè)務(wù)服務(wù)的端口不同)監(jiān)聽 pprof 請求:
import _ "net/http/pprof"
func initPprofMonitor() error {
pPort := global.Conf.MustInt("http_server", "pprofport", 8080)
var err error
addr := ":" + strconv.Itoa(pPort)
go func() {
err = http.ListenAndServe(addr, nil)
if err != nil {
logger.Error("funcRetErr=http.ListenAndServe||err=%s", err.Error())
}
}()
return err
}
pprof
包會(huì)自動(dòng)注冊 handler汪榔, 處理相關(guān)的請求:
// src/net/http/pprof/pprof.go:71
func init() {
http.Handle("/debug/pprof/", http.HandlerFunc(Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}
第一個(gè)路徑 /debug/pprof/
下面其實(shí)還有 5 個(gè)子路徑:
goroutine
threadcreate
heap
block
mutex
啟動(dòng)服務(wù)后,直接在瀏覽器訪問:
就可以得到一個(gè)匯總頁面:
可以直接點(diǎn)擊上面的鏈接肃拜,進(jìn)入子頁面痴腌,查看相關(guān)的匯總信息雌团。
關(guān)于 goroutine 的信息有兩個(gè)鏈接,goroutine
和 full goroutine stack dump
士聪,前者是一個(gè)匯總的消息锦援,可以查看 goroutines 的總體情況,后者則可以看到每一個(gè) goroutine 的狀態(tài)戚嗅。頁面具體內(nèi)容的解讀可以參考【大彬】的文章雨涛。
點(diǎn)擊 profile
和 trace
則會(huì)在后臺(tái)進(jìn)行一段時(shí)間的數(shù)據(jù)采樣,采樣完成后懦胞,返回給瀏覽器一個(gè) profile 文件替久,之后在本地通過 go tool pprof
工具進(jìn)行分析。
當(dāng)我們下載得到了 profile 文件后躏尉,執(zhí)行命令:
go tool pprof ~/Downloads/profile
就可以進(jìn)入命令行交互式使用模式蚯根。執(zhí)行 go tool pprof -help
可以查看幫助信息。
直接使用如下命令胀糜,則不需要通過點(diǎn)擊瀏覽器上的鏈接就能進(jìn)入命令行交互模式:
go tool pprof http://47.93.238.9:8080/debug/pprof/profile
當(dāng)然也是需要先后臺(tái)采集一段時(shí)間的數(shù)據(jù)颅拦,再將數(shù)據(jù)文件下載到本地,最后進(jìn)行分析教藻。上述的 Url 后面還可以帶上時(shí)間參數(shù):?seconds=60
距帅,自定義 CPU Profiling 的時(shí)長。
類似的命令還有:
# 下載 cpu profile括堤,默認(rèn)從當(dāng)前開始收集 30s 的 cpu 使用情況碌秸,需要等待 30s
go tool pprof http://47.93.238.9:8080/debug/pprof/profile
# wait 120s
go tool pprof http://47.93.238.9:8080/debug/pprof/profile?seconds=120
# 下載 heap profile
go tool pprof http://47.93.238.9:8080/debug/pprof/heap
# 下載 goroutine profile
go tool pprof http://47.93.238.9:8080/debug/pprof/goroutine
# 下載 block profile
go tool pprof http://47.93.238.9:8080/debug/pprof/block
# 下載 mutex profile
go tool pprof http://47.93.238.9:8080/debug/pprof/mutex
進(jìn)入交互式模式之后,比較常用的有 top
悄窃、list
讥电、web
等命令。
執(zhí)行 top
:
得到四列數(shù)據(jù):
列名 | 含義 |
---|---|
flat | 本函數(shù)的執(zhí)行耗時(shí) |
flat% | flat 占 CPU 總時(shí)間的比例轧抗。程序總耗時(shí) 16.22s, Eat 的 16.19s 占了 99.82% |
sum% | 前面每一行的 flat 占比總和 |
cum | 累計(jì)量恩敌。指該函數(shù)加上該函數(shù)調(diào)用的函數(shù)總耗時(shí) |
cum% | cum 占 CPU 總時(shí)間的比例 |
其他類型,如 heap 的 flat, sum, cum 的意義和上面的類似横媚,只不過計(jì)算的東西不同纠炮,一個(gè)是 CPU 耗時(shí),一個(gè)是內(nèi)存大小分唾。
執(zhí)行 list
抗碰,使用正則
匹配,找到相關(guān)的代碼:
list Eat
直接定位到了相關(guān)長耗時(shí)的代碼處:
執(zhí)行 web
(需要安裝 graphviz绽乔,pprof 能夠借助 grapgviz 生成程序的調(diào)用圖)弧蝇,會(huì)生成一個(gè) svg 格式的文件,直接在瀏覽器里打開(可能需要設(shè)置一下 .svg 文件格式的默認(rèn)打開方式):
圖中的連線代表對方法的調(diào)用,連線上的標(biāo)簽代表指定的方法調(diào)用的采樣值(例如時(shí)間看疗、內(nèi)存分配大小等)沙峻,方框的大小與方法運(yùn)行的采樣值的大小有關(guān)。
每個(gè)方框由兩個(gè)標(biāo)簽組成:在 cpu profile 中两芳,一個(gè)是方法運(yùn)行的時(shí)間占比摔寨,一個(gè)是它在采樣的堆棧中出現(xiàn)的時(shí)間占比(前者是 flat 時(shí)間,后者則是 cumulate 時(shí)間占比)怖辆;框越大是复,代表耗時(shí)越多或是內(nèi)存分配越多。
另外竖螃,traces
命令還可以列出函數(shù)的調(diào)用棧:
除了上面講到的兩種方式(報(bào)告生成淑廊、命令行交互),還可以在瀏覽器里進(jìn)行交互特咆。先生成 profile 文件季惩,再執(zhí)行命令:
go tool pprof --http=:8080 ~/Downloads/profile
進(jìn)入一個(gè)可視化操作界面:
點(diǎn)擊菜單欄可以在:Top/Graph/Peek/Source 之間進(jìn)行切換,甚至可以看到火焰圖(Flame Graph):
它和一般的火焰圖相比剛好倒過來了腻格,調(diào)用關(guān)系的展現(xiàn)是從上到下画拾。形狀越長,表示執(zhí)行時(shí)間越長菜职。注:我這里使用的 go 版本是 1.13青抛,更老一些的版本 pprof 工具不支持 -http
的參數(shù)。當(dāng)然也可以下載其他的庫查看火焰圖酬核,例如:
go get -u github.com/google/pprof
或者
go get github.com/uber/go-torch
pprof 進(jìn)階
我在參考資料部分給出了一些使用 pprof 工具進(jìn)行性能分析的實(shí)戰(zhàn)文章脂凶,可以跟著動(dòng)手實(shí)踐一下,之后再用到自己的平時(shí)工作中愁茁。
Russ Cox 實(shí)戰(zhàn)
這部分主要內(nèi)容來自參考資料【Ross Cox】,學(xué)習(xí)一下大牛的優(yōu)化思路亭病。
事情的起因是這樣的鹅很,有人發(fā)表了一篇文章,用各種語言實(shí)現(xiàn)了一個(gè)算法罪帖,結(jié)果用 go 寫的程序非常慢促煮,而 C++ 則最快。然后 Russ Cox 就鳴不平了整袁,哪受得了這個(gè)氣菠齿?馬上啟用 pprof 大殺器進(jìn)行優(yōu)化。最后坐昙,程序不僅更快绳匀,而且使用的內(nèi)存更少了!
首先,增加 cpu profiling 的代碼:
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
...
}
使用 pprof 觀察耗時(shí) top5
的函數(shù)疾棵,發(fā)現(xiàn)一個(gè)讀 map 的函數(shù)耗時(shí)最長:mapaccess1_fast64
戈钢,而它出現(xiàn)在一個(gè)遞歸函數(shù)中。
一眼就能看到框最大的 mapacess1_fast64
函數(shù)是尔。執(zhí)行 web mapaccess1
命令殉了,更聚焦一些:
調(diào)用 mapaccess1_fast64
函數(shù)最多的就是 main.FindLoops 和 main.DFS,是時(shí)候定位到具體的代碼了拟枚,執(zhí)行命令:list DFS
薪铜,定位到相關(guān)的代碼。
優(yōu)化的方法是將 map 改成 slice恩溅,能這樣做的原因當(dāng)然和 key 的類型是 int 而且不是太稀疏有關(guān)隔箍。
The take away will be that for smaller data sets, you shouldn’t use maps where slices would suffice, as maps have a large overhead.
修改完之后,再次通過 cpu profiling暴匠,發(fā)現(xiàn)遞歸函數(shù)的耗時(shí)已經(jīng)不在 top5 中了鞍恢。但是新增了長耗時(shí)函數(shù):runtime.mallocgc,占比 54.2%每窖,而這和分存分配以及垃圾回收相關(guān)帮掉。
下一步,增加采集內(nèi)存數(shù)據(jù)的代碼:
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
func main() {
// …………
FindHavlakLoops(cfgraph, lsgraph)
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal(err)
}
pprof.WriteHeapProfile(f)
f.Close()
return
}
// …………
}
繼續(xù)通過 top5
窒典、list
命令找到內(nèi)存分配最多的代碼位置蟆炊,發(fā)現(xiàn)這回是向 map 里插入元素使用的內(nèi)存比較多。改進(jìn)方式同樣是用 slice 代替 map瀑志,但 map 還有一個(gè)特點(diǎn)是可以重復(fù)插入元素涩搓,因此新寫了一個(gè)向 slice 插入元素的函數(shù):
func appendUnique(a []int, x int) []int {
for _, y := range a {
if x == y {
return a
}
}
return append(a, x)
}
好了,現(xiàn)在程序比最初的時(shí)候快了 2.1 倍劈猪。再次查看 cpu profile 數(shù)據(jù)昧甘,發(fā)現(xiàn) runtime.mallocgc
降了一些,但仍然占比 50.9%战得。
Another way to look at why the system is garbage collecting is to look at the allocations that are causing the collections, the ones that spend most of the time in mallocgc.
因此需要查看垃圾回收到底在回收哪些內(nèi)容充边,這些內(nèi)容就是導(dǎo)致頻繁垃圾回收的“罪魁禍?zhǔn)住薄?/p>
使用 web mallocgc
命令,將和 mallocgc 相關(guān)的函數(shù)用矢量圖的方式展現(xiàn)出來常侦,但是有太多樣本量很少的節(jié)點(diǎn)影響觀察浇冰,增加過濾命令:
go tool pprof --nodefraction=0.1 profile
將少于 10%
的采樣點(diǎn)過濾掉,新的矢量圖可以直觀地看出聋亡,FindLoops
觸發(fā)了最多的垃圾回收操作肘习。繼續(xù)使用命令 list FindLoops
直接找到代碼的位置。
原來坡倔,每次執(zhí)行 FindLoops
函數(shù)時(shí)漂佩,都要 make
一些臨時(shí)變量脖含,這會(huì)加重垃圾回收器的負(fù)擔(dān)。改進(jìn)方式是增加一個(gè)全局變量 cache仅仆,可以重復(fù)利用器赞。壞處是,現(xiàn)在不是線程安全的了墓拜。
使用 pprof 工具進(jìn)行的優(yōu)化到這就結(jié)束了港柜。最后的結(jié)果很不錯(cuò),基本上能達(dá)到和 C++ 同等的速度和同等的內(nèi)存分配大小咳榜。
我們能得到的啟發(fā)就是先使用 cpu profile 找出耗時(shí)最多的函數(shù)夏醉,進(jìn)行優(yōu)化。如果發(fā)現(xiàn) gc 執(zhí)行比較多的時(shí)候涌韩,找出內(nèi)存分配最多的代碼以及引發(fā)內(nèi)存分配的函數(shù)畔柔,進(jìn)行優(yōu)化。
原文很精彩臣樱,雖然寫作時(shí)間比較久遠(yuǎn)(最初寫于 2011 年)了靶擦,但仍然值得一看。另外雇毫,參考資料【wolfogre】的實(shí)戰(zhàn)文章也非常精彩玄捕,而且用的招式和這篇文章差不多,但是你可以運(yùn)行文章提供的樣例程序棚放,一步步地解決性能問題枚粘,很有意思!
查找內(nèi)存泄露
內(nèi)存分配既可以發(fā)生在堆上也可以在棧上飘蚯。堆上分配的內(nèi)存需要垃圾回收或者手動(dòng)回收(對于沒有垃圾回收的語言馍迄,例如 C++),棧上的內(nèi)存則通常在函數(shù)退出后自動(dòng)釋放局骤。
Go 語言通過逃逸分析會(huì)將盡可能多的對象分配到棧上攀圈,以使程序可以運(yùn)行地更快。
這里說明一下峦甩,有兩種內(nèi)存分析策略:一種是當(dāng)前的(這一次采集)內(nèi)存或?qū)ο蟮姆峙淞砍校Q為 inuse
;另一種是從程序運(yùn)行到現(xiàn)在所有的內(nèi)存分配穴店,不管是否已經(jīng)被 gc 過了,稱為 alloc
拿穴。
As mentioned above, there are two main memory analysis strategies with pprof. One is around looking at the current allocations (bytes or object count), called inuse. The other is looking at all the allocated bytes or object count throughout the run-time of the program, called alloc. This means regardless if it was gc-ed, a summation of everything sampled.
加上 -sample_index
參數(shù)后泣洞,可以切換內(nèi)存分析的類型:
go tool pprof -sample_index=alloc_space http://47.93.238.9:8080/debug/pprof/heap
共有 4 種:
類型 | 含義 |
---|---|
inuse_space | amount of memory allocated and not released yet |
inuse_objects | amount of objects allocated and not released yet |
alloc_space | total amount of memory allocated (regardless of released) |
alloc_objects | total amount of objects allocated (regardless of released) |
參考資料【大彬 實(shí)戰(zhàn)內(nèi)存泄露】講述了如何通過類似于 diff 的方式找到前后兩個(gè)時(shí)刻多出的 goroutine,進(jìn)而找到 goroutine 泄露的原因默色,并沒有直接使用 heap 或者 goroutine 的 profile 文件球凰。同樣推薦閱讀!
總結(jié)
pprof
是進(jìn)行 Go 程序性能分析的有力工具,它通過采樣呕诉、收集運(yùn)行中的 Go 程序性能相關(guān)的數(shù)據(jù)缘厢,生成 profile 文件。之后甩挫,提供三種不同的展現(xiàn)形式贴硫,讓我們能更直觀地看到相關(guān)的性能數(shù)據(jù)。
得到性能數(shù)據(jù)后伊者,可以使用 top
英遭、web
、list
等命令迅速定位到相應(yīng)的代碼處亦渗,并進(jìn)行優(yōu)化挖诸。
“過早的優(yōu)化是萬惡之源”。實(shí)際工作中法精,很少有人會(huì)關(guān)注性能多律,但當(dāng)你寫出的程序存在性能瓶頸,qa 壓測時(shí)搂蜓,qps 上不去狼荞,為了展示一下技術(shù)實(shí)力,還是要通過 pprof 觀察性能瓶頸洛勉,進(jìn)行相應(yīng)的性能優(yōu)化粘秆。
參考資料
【Russ Cox 優(yōu)化過程,并附上代碼】https://blog.golang.org/profiling-go-programs
【google pprof】https://github.com/google/pprof
【使用 pprof 和火焰圖調(diào)試 golang 應(yīng)用】https://cizixs.com/2017/09/11/profiling-golang-program/
【資源合集】https://jvns.ca/blog/2017/09/24/profiling-go-with-pprof/
【Profiling your Golang app in 3 steps】https://coder.today/tech/2018-11-10_profiling-your-golang-app-in-3-steps/
【案例收毫,壓測 Golang remote profiling and flamegraphs】https://matoski.com/article/golang-profiling-flamegraphs/
【煎魚 pprof】https://segmentfault.com/a/1190000016412013
【鳥窩 pprof】https://colobu.com/2017/03/02/a-short-survey-of-golang-pprof/
【關(guān)于 Go 的 7 種性能分析方法】https://blog.lab99.org/post/golang-2017-10-20-video-seven-ways-to-profile-go-apps.html
【pprof 比較全】https://juejin.im/entry/5ac9cf3a518825556534c76e
【通過實(shí)例來講解分析攻走、優(yōu)化過程】https://artem.krylysov.com/blog/2017/03/13/profiling-and-optimizing-go-web-applications/
【Go 作者 Dmitry Vyukov】https://github.com/golang/go/wiki/Performance
【wolfogre 非常精彩的實(shí)戰(zhàn)文章】https://blog.wolfogre.com/posts/go-ppof-practice/
【dave.cheney】https://dave.cheney.net/high-performance-go-workshop/dotgo-paris.html
【實(shí)戰(zhàn)案例】https://www.cnblogs.com/sunsky303/p/11058808.html
【大彬 實(shí)戰(zhàn)內(nèi)存泄露】https://segmentfault.com/a/1190000019222661
【查找內(nèi)存泄露】https://www.freecodecamp.org/news/how-i-investigated-memory-leaks-in-go-using-pprof-on-a-large-codebase-4bec4325e192/
【雷神 3 性能優(yōu)化】https://diducoder.com/sotry-about-sqrt.html
本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布!