成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

生產(chǎn)環(huán)境Go程序內(nèi)存泄露,用pprof如何快速定位

開發(fā)
Golang 為我們提供了 pprof 工具。掌握之后,可以幫助排查程序的內(nèi)存泄露問題,當(dāng)然除了排查內(nèi)存,它也能排查 CPU 占用過高。

內(nèi)存泄漏可以在整個(gè)系統(tǒng)中以多種形式出現(xiàn),除了在寫代碼上的疏忽,忘了關(guān)閉該關(guān)閉的資源外,更多的時(shí)候?qū)е孪到y(tǒng)發(fā)生內(nèi)存泄露原因可能是設(shè)計(jì)上決策不對、或者業(yè)務(wù)邏輯上的疏忽沒有考慮到一些邊界條件。

比如查數(shù)據(jù)庫時(shí),有個(gè)查詢條件在一定情況下應(yīng)用不到,導(dǎo)致程序被迫持有一個(gè)超大的結(jié)果集,這樣持續(xù)一段時(shí)間,執(zhí)行相同任務(wù)的線程一多,就會(huì)造成內(nèi)存泄露。

Golang 為我們提供了 pprof 工具。掌握之后,可以幫助排查程序的內(nèi)存泄露問題,當(dāng)然除了排查內(nèi)存,它也能排查 CPU 占用過高,線程死鎖的這些問題,不過這篇文章我們會(huì)聚焦在怎么用 pprof 排查程序的內(nèi)存泄露問題。

Go 開發(fā)的系統(tǒng)中,怎么 添加 pprof 進(jìn)行采樣的步驟,在這里我就不再細(xì)說了,因?yàn)槲抑暗奈恼?,?pprof 的安裝和使用做了詳細(xì)的說明,文章鏈接我放在這里:

  • Golang 程序性能分析(一)pprof 和 火焰圖分析https://mp.weixin.qq.com/s?__biz=MzUzNTY5MzU2MA==&mid=2247486618&idx=1&sn=bb5e76e011ba99ebc2ffb8f9d3c00b89&scene=21#wechat_redirect
  • Golang程序性能分析(二)在Echo和Gin框架中使用pprofhttps://mp.weixin.qq.com/s?__biz=MzUzNTY5MzU2MA==&mid=2247486654&idx=1&sn=ea7171f58254dfecebc61cfbec7b64e5&scene=21#wechat_redirect
  • Golang程序性能分析(三)用pprof分析gRPC服務(wù)的性能https://mp.weixin.qq.com/s?__biz=MzUzNTY5MzU2MA==&mid=2247486669&idx=1&sn=2be1d2cb1b85c8d0f59a314cafb4637f&scene=21#wechat_redirect

當(dāng)然如果你想嘗試點(diǎn)更智能的,讓程序能自己監(jiān)控自己,并在出現(xiàn)抖動(dòng)的時(shí)候自己采樣,Dump 出導(dǎo)致內(nèi)存、CPU的問題調(diào)用棧信息,可以看一下下面兩篇文章里我介紹的方法和實(shí)用的類庫。

  • 學(xué)會(huì)這幾招讓 Go 程序自己監(jiān)控自己https://mp.weixin.qq.com/s?__biz=MzUzNTY5MzU2MA==&mid=2247490745&idx=1&sn=6a04327f98a734fd50e509362fc04d48&scene=21#wechat_redirect
  • Go 服務(wù)進(jìn)行自動(dòng)采樣性能分析的方案設(shè)計(jì)與實(shí)現(xiàn)https://mp.weixin.qq.com/s?__biz=MzUzNTY5MzU2MA==&mid=2247491713&idx=1&sn=3735d8f028823eaca6f42b28a9e7d817&scene=21#wechat_redirect

內(nèi)存泄露該看哪個(gè)指標(biāo)

pprof?工具集,提供了Go程序內(nèi)部多種性能指標(biāo)的采樣能力,我們常會(huì)用到的性能采樣指標(biāo)有這些:

  • profile:CPU采樣
  • heap:堆中活躍對象的內(nèi)存分配情況的采樣
  • goroutine:當(dāng)前所有g(shù)oroutine的堆棧信息
  • allocs: 會(huì)采樣自程序啟動(dòng)所有對象的內(nèi)存分配信息(包括已經(jīng)被GC回收的內(nèi)存)
  • threadcreate:采樣導(dǎo)致創(chuàng)建新系統(tǒng)線程的堆棧信息

上面 heap 和 allocs 是兩個(gè)與內(nèi)存相關(guān)的指標(biāo), allocs 指標(biāo)會(huì)采樣自程序啟動(dòng)所有對象的內(nèi)存分配信息。一般是在想要分析哪些代碼能優(yōu)化提高效率時(shí),查看的指標(biāo)。針對查看內(nèi)存泄露問題的分析,使用則的是 heap 指標(biāo)里的采樣信息。

Heap

pprof 的 heap 信息,是對堆中活躍對象的內(nèi)存分配情況的采樣。Go 里邊哪些對象會(huì)被分配到堆上?一般概況就是,被多個(gè)函數(shù)引用的對象、全局變量、超過一定體積(32KB)的對象都會(huì)被分配到堆上,當(dāng)然對于 Go 來說還會(huì)有其他的一些情況會(huì)讓對象逃逸到堆上。

具體哪些變量會(huì)被分配到堆上、以及內(nèi)存逃逸的事兒,就不多說了,想看詳細(xì)情況的,看下面這兩篇文章。

  • 圖解Go內(nèi)存管理器的內(nèi)存分配策略
  • Go內(nèi)存管理之代碼的逃逸分析

Heap 采樣

要使用 pprof 獲取 heap 指標(biāo)的采樣信息,一種情況是使用 "net/http/pprof" 包

import (
"net/http/pprof"
)

func main() {
http.HandleFunc("/debug/pprof/heap", pprof.Index)
......
http.ListenAndServe(":80", nil)
}

然后通過 HTTP 請求的方式獲得

curl -sK -v https://example.com/debug/pprof/profile > heap.out

還有一種主要的方法是使用runtime.pprof  提供的方法,把采樣信息保存到文件。

pprof.Lookup("heap").WriteTo(profile_file, 0)

關(guān)于這兩個(gè)包的使用方式,以及怎么把信息采樣到文件,上面介紹自動(dòng)采樣的文章里有詳細(xì)的介紹,這里就不再花過多篇幅了。

下面進(jìn)入文章的正題, 拿到采樣文件后,怎么用 pprof 排查出代碼哪里導(dǎo)致了內(nèi)存泄露。

用 pprof 找出內(nèi)存泄露的地方

pprof 在采樣 heap 指標(biāo)的信息時(shí),使用的是 runtime.MemProfile 函數(shù),該函數(shù)默認(rèn)收集每個(gè) 512KB 已分配字節(jié)的分配信息。我們可以設(shè)置讓 runtime.MemProfile 收集所有對象的信息,不過這會(huì)對程序的性能造成影響。

當(dāng)我們拿到采樣文件后,就可以通過 go tool pprof 將信息加載到一個(gè)交互模式的控制臺(tái)中。

> go tool pprof heap.out

進(jìn)入,交互式控制臺(tái)后,一般會(huì)有如下的提示:

File: heap.out
Type: inuse_space
Time: Feb 1, 2022 at 10:11am (CST)
Entering interactive mode (type "help" for commands, "o" for options)

這里的 Type: inuse_space  指明了文件內(nèi)采樣信息的類型, Type 可能的值有:

  • inuse_space — 已分配但尚未釋放的內(nèi)存空間
  • inuse_objects——已分配但尚未釋放的對象數(shù)量
  • alloc_space — 分配的內(nèi)存總量(已釋放的也會(huì)統(tǒng)計(jì))
  • alloc_objects — 分配的對象總數(shù)(無論是否釋放)

接下來,介紹一個(gè) pprof 交互式模式下的命令 top,也可以是 topN,比如 top10。這個(gè)跟Linux 系統(tǒng)的 top 命令類似,輸出 Top N 個(gè)最占用內(nèi)存的函數(shù)。

(pprof) top10
Showing nodes accounting for 134.55MB, 92.16% of 145.99MB total
Dropped 60 nodes (cum <= 0.73MB)
Showing top 10 nodes out of 117
flat flat% sum% cum cum%
60.53MB 41.46% 41.46% 85.68MB 58.69% github.com/jinzhu/gorm.glob..func2
18.65MB 12.77% 54.24% 18.65MB 12.77% regexp.(*Regexp).Split
16.95MB 11.61% 65.84% 16.95MB 11.61% github.com/jinzhu/gorm.(*Scope).AddToVars
8.67MB 5.94% 71.78% 129.05MB 88.39% example.com/xxservice/dummy.GetLargeData
7.50MB 5.14% 82.63% 7.50MB 5.14% reflect.packEface
6.50MB 4.45% 87.08% 6.50MB 4.45% fmt.Sprintf
4MB 2.74% 89.82% 4MB 2.74% runtime.malg
1.91MB 1.31% 91.13% 1.91MB 1.31% strings.Replace
1.51MB 1.03% 92.16% 1.51MB 1.03% bytes.makeSlice

在這兩個(gè)里邊,最占用內(nèi)存的前三是 gorm 庫的一個(gè)方法,gorm 是個(gè) ORM 庫,但是導(dǎo)致它內(nèi)存泄露的原因應(yīng)該是后面一個(gè)有業(yè)務(wù)邏輯的代碼,dummy.GetLargeData 方法。

在 top 指令輸出的列表中,我們可以看到兩個(gè)值,flat 和 cum。

  • flat:表示此函數(shù)分配、并由該函數(shù)持有的內(nèi)存空間。
  • cum:表示由這個(gè)函數(shù)或它調(diào)用堆棧下面的函數(shù)分配的內(nèi)存總量。

此外 sum % 表示前面幾行輸出的 flat百分比之和, 比如上面第四行 sum% 列的值是, 71.78%  實(shí)際上就是它以及它上面三行輸出的 flat% 的總和。

定位到導(dǎo)致內(nèi)存泄露的函數(shù)后,后面要做的優(yōu)化問題就是,深入函數(shù)內(nèi)部,看哪里使用不當(dāng)或者有邏輯上的疏忽,比如我開頭舉得那個(gè)查詢條件在有些情況下應(yīng)用不上的例子。

當(dāng)然如果你想在函數(shù)內(nèi)部再精確的定位到底是哪段代碼導(dǎo)致的內(nèi)存溢出,也是有辦法的,這時(shí)候就需要用到 list 指令了。

list 指令可以列出函數(shù)內(nèi)部,每一行代碼運(yùn)行時(shí)分配的內(nèi)存(如果分析CPU的采樣文件,則會(huì)顯示CPU使用時(shí)間)

(pprof) list dummy.GetLargeData
Total: 814.62MB
ROUTINE ======================== dummy.GetLargeData in /home/xxx/xxx/xxx.go
814.62MB 814.62MB (flat, cum) 100% of Total
. . 20: }()
. . 21:
. . 22: tick := time.Tick(time.Second / 100)
. . 23: var buf []byte
. . 24: for range tick {
814.62MB 814.62MB 25: buf = append(buf, make([]byte, 1024*1024)...)
. . 26: }
. . 27:}
. . 28:

總結(jié)

這里把用 pprof 怎么排查程序的內(nèi)存泄露做了個(gè)簡單的總結(jié),當(dāng)然如果你們公司有條件上持續(xù)采樣,或者我之前文章說的自動(dòng)采樣方案的話,最好還是用上,讓機(jī)器幫我們做這些事情。?

不過不管是用什么辦法,最終只能是幫我們定位出來哪里造成了內(nèi)存泄露,至于要怎么優(yōu)化解決這個(gè)問題,還得具體情況具體分析,如果是一些業(yè)務(wù)邏輯實(shí)現(xiàn)上的問題,那就得跟團(tuán)隊(duì)商量一下實(shí)現(xiàn)方式,可能還會(huì)涉及到產(chǎn)品上的一些改動(dòng)。

責(zé)任編輯:張燕妮 來源: KevinYan11
相關(guān)推薦

2022-02-07 08:55:57

Go程序代碼

2021-04-14 10:14:34

JVM生產(chǎn)問題定位內(nèi)存泄露

2021-04-29 09:20:50

GoPProf工具

2022-10-10 11:37:14

Gomap內(nèi)存

2024-12-05 08:58:47

2019-11-05 08:24:34

JavaOOM快速定位

2020-07-08 09:50:37

Java內(nèi)存快速定位

2020-06-23 09:48:09

Python開發(fā)內(nèi)存

2017-12-11 11:00:27

內(nèi)存泄露判斷

2013-04-09 14:49:18

Linux內(nèi)存統(tǒng)計(jì)內(nèi)存泄露

2017-10-26 08:43:18

JavaScript內(nèi)存處理

2015-12-07 09:39:27

Java內(nèi)存泄露

2019-12-20 09:12:37

內(nèi)存工程師網(wǎng)絡(luò)

2020-03-31 17:05:39

Redis熱 key代理

2025-04-09 09:31:29

2021-10-08 11:05:00

Go 切片內(nèi)存

2010-11-05 13:02:58

內(nèi)存iPhone

2019-09-29 00:25:11

CC++內(nèi)存泄漏

2022-05-13 23:46:52

GO編程內(nèi)存

2011-09-19 10:43:19

Nuget
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 精品国产乱码一区二区三区 | 中文字幕日韩一区 | 盗摄精品av一区二区三区 | 97国产一区二区 | 亚洲成人一级片 | 国产一区二区三区四区在线观看 | 欧美久久久久 | 欧美日本在线观看 | 欧美成人一区二区 | 久久激情av| 国产精品国产三级国产aⅴ无密码 | 欧美精品区 | 国产精品欧美一区喷水 | 手机看片在线播放 | 91大神在线看 | 亚洲最大的成人网 | 人人鲁人人莫人人爱精品 | 国产 欧美 日韩 一区 | 午夜小视频免费观看 | 中文字幕黄色大片 | 91精品一区二区三区久久久久久 | 在线播放中文字幕 | 久久精品一级 | 国产成人精品一区二区三区在线 | 好好的日在线视频 | 成人亚洲片 | 在线视频99 | 在线观看av网站永久 | 成年人在线视频 | 亚洲激情自拍偷拍 | 国产精品免费一区二区三区四区 | a级在线观看 | 亚洲精品日韩一区二区电影 | 久久久高清 | 国产激情91久久精品导航 | 国产aaaaav久久久一区二区 | 搞黄网站在线观看 | 色综合一区二区三区 | 日韩精品中文字幕一区二区三区 | 欧美成人aaa级毛片在线视频 | 成人在线中文字幕 |