Go語(yǔ)言之使用pprof工具查找goroutine(協(xié)程)泄漏
用pprof工具查找goroutine(協(xié)程)泄漏
goroutine泄漏指的是goroutine啟動(dòng)之后沒(méi)有退出導(dǎo)致goroutine的數(shù)量持續(xù)上升,或者是在實(shí)際應(yīng)用中g(shù)oroutine占用了很長(zhǎng)時(shí)間才退出導(dǎo)致在一段時(shí)間內(nèi)goroutine的數(shù)量急劇上升。
通??梢圆捎肎o自帶的pprof工具來(lái)定位問(wèn)題
如下面這個(gè)示例
這是一個(gè)簡(jiǎn)單的HTTP服務(wù),當(dāng)接收到請(qǐng)求時(shí)另起一個(gè)goroutine來(lái)輸出日志,同時(shí)返回“Hello, World!\n”。
在記錄日志之前可能要處理一個(gè)耗時(shí)很長(zhǎng)的業(yè)務(wù)邏輯,如通過(guò)公網(wǎng)請(qǐng)求第三方的API接口,這里為了簡(jiǎn)化問(wèn)題用time.Sleep來(lái)示意。
goroutineleak.go
package main import ( "io" "log" "net/http" _ "net/http/pprof" "time" ) func writeLog(msg string) { go func() { time.Sleep(1 * time.Second) log.Println(msg) }() } func handler(w http.ResponseWriter, r *http.Request) { writeLog(r.URL.RequestURI()) io.WriteString(w, "Hello, world!\n") } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) }
利用Grinder來(lái)壓測(cè),開(kāi)8個(gè)進(jìn)程,每個(gè)進(jìn)程開(kāi)3個(gè)線程,同時(shí)請(qǐng)求上述服務(wù)。
在請(qǐng)求過(guò)程中,通過(guò)瀏覽器查看http://pub.pengpengzhou.com:8080/debug/pprof/goroutine?debug=1, 域名是上述服務(wù)所在的地址。
從pprof的返回結(jié)果中,我們可以看到協(xié)程總數(shù)是5605,下面列出了5組產(chǎn)生協(xié)程的代碼stack trace,按產(chǎn)生的協(xié)程數(shù)量倒排序。
可以看到第一組產(chǎn)生了5597個(gè)協(xié)程,產(chǎn)生位置在goroutineleak.go的13行“time.Sleep(1 * time.Second)”對(duì)應(yīng)的函數(shù)是main.writeLog。
問(wèn)題很快得到定位,把這一行注釋掉,重新再壓測(cè),可以得到如下結(jié)果, 協(xié)程總數(shù)一下就降到了8,泄漏的問(wèn)題得到了解決。
當(dāng)然,在實(shí)際應(yīng)用中,耗時(shí)是不可避免的,通常是用設(shè)置超時(shí)的辦法來(lái)規(guī)避長(zhǎng)時(shí)間等待。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
goland中導(dǎo)包報(bào)紅和go mod問(wèn)題
這篇文章主要介紹了goland中導(dǎo)包報(bào)紅和go mod問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Go中使用操作符進(jìn)行數(shù)學(xué)運(yùn)算的示例代碼
在編程中有效地執(zhí)行數(shù)學(xué)運(yùn)算是一項(xiàng)需要開(kāi)發(fā)的重要技能,本文主要介紹了Go中使用操作符進(jìn)行數(shù)學(xué)運(yùn)算的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10go+redis實(shí)現(xiàn)消息隊(duì)列發(fā)布與訂閱的詳細(xì)過(guò)程
這篇文章主要介紹了go+redis實(shí)現(xiàn)消息隊(duì)列發(fā)布與訂閱,redis做消息隊(duì)列的缺點(diǎn):沒(méi)有持久化,一旦消息沒(méi)有人消費(fèi),積累到一定程度后就會(huì)丟失,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09Go語(yǔ)言做爬蟲(chóng)狀態(tài)碼返回418的問(wèn)題解決
在使用Go語(yǔ)言做爬蟲(chóng)時(shí),使用http.Get(url)去獲取網(wǎng)頁(yè)內(nèi)容,狀態(tài)碼返回404,本文我們就詳細(xì)的介紹一下解決方法,感興趣的可以了解一下2021-12-12go引入自建包名報(bào)錯(cuò):package?XXX?is?not?in?std解決辦法
這篇文章主要給大家介紹了go引入自建包名報(bào)錯(cuò):package?XXX?is?not?in?std的解決辦法,這是在寫(xiě)測(cè)試引入包名的時(shí)候遇到的錯(cuò)誤提示,文中將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12Golang極簡(jiǎn)入門(mén)教程(四):編寫(xiě)第一個(gè)項(xiàng)目
這篇文章主要介紹了Golang極簡(jiǎn)入門(mén)教程(四):編寫(xiě)第一個(gè)項(xiàng)目,本文講解了workspace、包路徑、第一個(gè)可執(zhí)行命令等內(nèi)容,需要的朋友可以參考下2014-10-10golang 調(diào)用c語(yǔ)言動(dòng)態(tài)庫(kù)方式實(shí)現(xiàn)
本文主要介紹了golang 調(diào)用c語(yǔ)言動(dòng)態(tài)庫(kù)方式實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12golang使用sync.Once實(shí)現(xiàn)懶加載的用法和坑點(diǎn)詳解
這篇文章主要為大家詳細(xì)介紹了golang使用sync.Once實(shí)現(xiàn)懶加載的用法和坑點(diǎn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11深入剖析Go語(yǔ)言編程中switch語(yǔ)句的使用
這篇文章主要介紹了Go語(yǔ)言編程中switch語(yǔ)句的使用,是Go語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-10-10Golang庫(kù)插件注冊(cè)加載機(jī)制的問(wèn)題
這篇文章主要介紹了Golang庫(kù)插件注冊(cè)加載機(jī)制,這里說(shuō)的插件并不是指的golang原生的可以在buildmode中加載指定so文件的那種加載機(jī)制,需要的朋友可以參考下2022-03-03