這篇文章主要介紹“go pprof如何使用”,在日常操作中,相信很多人在go pprof如何使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”go pprof如何使用”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
公司主營業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出吉木乃免費(fèi)做網(wǎng)站回饋大家。
pprof是Go的性能分析工具,在程序運(yùn)行過程中,可以記錄程序的運(yùn)行信息,可以是CPU使用情況、內(nèi)存使用情況、goroutine運(yùn)行情況等,當(dāng)需要性能調(diào)優(yōu)或者定位Bug時候,這些記錄的信息是相當(dāng)重要。使用pprof有多種方式,Go已經(jīng)現(xiàn)成封裝好了1個“net/http/pprof”,使用簡單的幾行命令,就可以開啟pprof,記錄運(yùn)行信息,并且提供了Web服務(wù)。
profile 一般被稱為 性能分析,詞典上的翻譯是 概況(名詞)或者 描述…的概況(動詞)。對于計(jì)算機(jī)程序來說,它的 profile,就是一個程序在運(yùn)行時的各種概況信息,包括 cpu 占用情況,內(nèi)存情況,線程情況,線程阻塞情況等等。知道了程序的這些信息,也就能容易的定位程序中的問題和故障原因 。
pprof是Go的性能分析工具,在程序運(yùn)行過程中,可以記錄程序的運(yùn)行信息,可以是CPU使用情況、內(nèi)存使用情況、goroutine運(yùn)行情況等,當(dāng)需要性能調(diào)優(yōu)或者定位Bug時候,這些記錄的信息是相當(dāng)重要。
golang 對于 profiling 支持的比較好,標(biāo)準(zhǔn)庫就提供了profile庫 “runtime/pprof” 和 “net/http/pprof”,而且也提供了很多好用的可視化工具來輔助開發(fā)者做 profiling。
對于在線服務(wù),對于一個 HTTP Server,訪問 pprof 提供的 HTTP 接口,獲得性能數(shù)據(jù)。當(dāng)然,實(shí)際上這里底層也是調(diào)用的 runtime/pprof 提供的函數(shù),封裝成接口對外提供網(wǎng)絡(luò)訪問,本文主要介紹"net/http/pprof"的使用。
使用pprof有多種方式,Go已經(jīng)現(xiàn)成封裝好了1個:net/http/pprof,使用簡單的幾行命令,就可以開啟pprof,記錄運(yùn)行信息,并且提供了Web服務(wù),能夠通過瀏覽器和命令行2種方式獲取運(yùn)行數(shù)據(jù)。
web服務(wù)中如何開啟監(jiān)控,來看一個簡單的例子。
package main
import (
"fmt"
"net/http"
_ "net/http/pprof"
)
func main() {
// 開啟pprof,監(jiān)聽請求
ip := "0.0.0.0:8080"
if err := http.ListenAndServe(ip, nil); err != nil {
fmt.Printf("start pprof failed on %s\n", ip)
}
dosomething()
}
在程序中導(dǎo)入 "net/http/pprof"包,并打開監(jiān)聽端口,這時候便可以獲取程序的profile,在實(shí)際生產(chǎn)中,我們一般將這個功能封裝成一個goroutine。那么開啟之后如何查看呢?有三種方式:
打開一個瀏覽器輸入 ip:port/debug/pprof,回車。
pprof會提供很多性能數(shù)據(jù)。具體含義為:
allocs:內(nèi)存分配情況的采樣信息
blocks:阻塞操作情況的采樣信息 cmdline:程序啟動命令及其參數(shù)
goroutine:當(dāng)前所有協(xié)程的堆棧信息
heap:堆上內(nèi)存的使用情況的采樣信息 mutex:鎖爭用情況的采樣信息
profile:cpu占用情況的采樣信息
threadcreate:系統(tǒng)線程創(chuàng)建情況的采樣信息
trace:程序運(yùn)行的跟蹤信息
allocs是所有對象的內(nèi)存分配,heap是活躍對象的內(nèi)存分配,后文會有詳細(xì)的描述。
1、當(dāng) CPU 性能分析啟用后,Go runtime 會每 10ms 就暫停一下,記錄當(dāng)前運(yùn)行的 goroutine 的調(diào)用堆棧及相關(guān)數(shù)據(jù)。當(dāng)性能分析數(shù)據(jù)保存到硬盤后,我們就可以分析代碼中的熱點(diǎn)了。
2、內(nèi)存性能分析則是在堆(Heap)分配的時候,記錄一下調(diào)用堆棧。默認(rèn)情況下,是每 1000 次分配,取樣一次,這個數(shù)值可以改變。棧(Stack)分配 由于會隨時釋放,因此不會被內(nèi)存分析所記錄。由于內(nèi)存分析是取樣方式,并且也因?yàn)槠溆涗浀氖欠峙鋬?nèi)存,而不是使用內(nèi)存。因此使用內(nèi)存性能分析工具來準(zhǔn)確判斷程序具體的內(nèi)存使用是比較困難的。
3、阻塞分析是一個很獨(dú)特的分析,它有點(diǎn)兒類似于 CPU 性能分析,但是它所記錄的是 goroutine 等待資源所花的時間。阻塞分析對分析程序并發(fā)瓶頸非常有幫助,阻塞性能分析可以顯示出什么時候出現(xiàn)了大批的 goroutine 被阻塞了。阻塞性能分析是特殊的分析工具,在排除 CPU 和內(nèi)存瓶頸前,不應(yīng)該用它來分析。
當(dāng)然,如果你點(diǎn)進(jìn)任何一個鏈接,便會發(fā)現(xiàn),可讀性差,幾乎無法分析。如圖:
點(diǎn)擊heap,拉到最底部,可以看到一些有意思的數(shù)據(jù),有時候也有可能會對問題排查有幫助,但一般不用。
heap profile: 3190: 77516056 [54762: 612664248] @ heap/1048576
1: 29081600 [1: 29081600] @ 0x89368e 0x894cd9 0x8a5a9d 0x8a9b7c 0x8af578 0x8b4441 0x8b4c6d 0x8b8504 0x8b2bc3 0x45b1c1
# 0x89368d github.com/syndtr/goleveldb/leveldb/memdb.(*DB).Put+0x59d
# 0x894cd8 xxxxx/storage/internal/memtable.(*MemTable).Set+0x88
# 0x8a5a9c xxxxx/storage.(*snapshotter).AppendCommitLog+0x1cc
# 0x8a9b7b xxxxx/storage.(*store).Update+0x26b
# 0x8af577 xxxxx/config.(*config).Update+0xa7
# 0x8b4440 xxxxx/naming.(*naming).update+0x120
# 0x8b4c6c xxxxx/naming.(*naming).instanceTimeout+0x27c
# 0x8b8503 xxxxx/naming.(*naming).(xxxxx/naming.instanceTimeout)-fm+0x63
......
# runtime.MemStats
# Alloc = 2463648064
# TotalAlloc = 31707239480
# Sys = 4831318840
# Lookups = 2690464
# Mallocs = 274619648
# Frees = 262711312
# HeapAlloc = 2463648064
# HeapSys = 3877830656
# HeapIdle = 854990848
# HeapInuse = 3022839808
# HeapReleased = 0
# HeapObjects = 11908336
# Stack = 655949824 / 655949824
# MSpan = 63329432 / 72040448
# MCache = 38400 / 49152
# BuckHashSys = 1706593
# GCSys = 170819584
# OtherSys = 52922583
# NextGC = 3570699312
# PauseNs = [1052815 217503 208124 233034 ......]
# NumGC = 31
# DebugGC = false
Sys: 進(jìn)程從系統(tǒng)獲得的內(nèi)存空間,虛擬地址空間
HeapAlloc:進(jìn)程堆內(nèi)存分配使用的空間,通常是用戶new出來的堆對象,包含未被gc掉的。
HeapSys:進(jìn)程從系統(tǒng)獲得的堆內(nèi)存,因?yàn)間olang底層使用TCmalloc機(jī)制,會緩存一部分堆內(nèi)存,虛擬地址空間
PauseNs:記錄每次gc暫停的時間(納秒),最多記錄256個最新記錄。
NumGC: 記錄gc發(fā)生的次數(shù)
除了瀏覽器,Go還提供了命令行的方式,能夠獲取以上信息,這種方式用起來更方便。
使用命令go tool pprof url
可以獲取指定的profile文件,此命令會發(fā)起http請求,然后下載數(shù)據(jù)到本地,之后進(jìn)入交互式模式,就像gdb一樣,可以使用命令查看運(yùn)行信息,以下為使用示例:
# 下載cpu profile,默認(rèn)從當(dāng)前開始收集30s的cpu使用情況,需要等待30s
go tool pprof http://localhost:8080/debug/pprof/profile # 30-second CPU profile
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=120 # wait 120s
# 下載heap profile
go tool pprof http://localhost:8080/debug/pprof/heap # heap profile
# 下載goroutine profile
go tool pprof http://localhost:8080/debug/pprof/goroutine # goroutine profile
# 下載block profile
go tool pprof http://localhost:8080/debug/pprof/block # goroutine blocking profile
# 下載mutex profile
go tool pprof http://localhost:8080/debug/pprof/mutex
接下來用一個例子來說明最常用的四個命令:web、top、list、traces
。
接下來以內(nèi)存分析舉例,cpu和goroutine等分析同理,讀者可以自行舉一反三。
首先,我們通過命令go tool pprof url
獲取指定的profile/heap文件,隨后自動進(jìn)入命令行。如圖:
第一步,我們首先輸入web
命令,這時瀏覽器會彈出各個函數(shù)之間的調(diào)用圖,以及內(nèi)存的之間的關(guān)系。如圖:
這個圖的具體讀法,可參照:中文文檔 或者英文文檔 這里不多贅述。只需要了解越紅越大的方塊,有問題的可能性就越大,代表可能占用了更多的內(nèi)存,如果在cpu的圖中代表消耗了更多cpu資源,以此類推。
接下來 top、list、traces
三步走可以看出很多想要的結(jié)果。
top按指標(biāo)大小列出前10個函數(shù),比如內(nèi)存是按內(nèi)存占用多少,CPU是按執(zhí)行時間多少。
top會列出5個統(tǒng)計(jì)數(shù)據(jù):
flat: 本函數(shù)占用的內(nèi)存量。
flat%: 本函數(shù)內(nèi)存占使用中內(nèi)存總量的百分比。
sum%: 之前函數(shù)flat的累計(jì)和。
cum:是累計(jì)量,假如main函數(shù)調(diào)用了函數(shù)f,函數(shù)f占用的內(nèi)存量,也會記進(jìn)來。
cum%: 是累計(jì)量占總量的百分比。
這樣我們可以看到到底是具體哪些函數(shù)占用了多少內(nèi)存。
當(dāng)然top后也可以接參數(shù),top n
可以列出前n個函數(shù)。
list可以查看某個函數(shù)的代碼,以及該函數(shù)每行代碼的指標(biāo)信息,如果函數(shù)名不明確,會進(jìn)行模糊匹配,比如list main
會列出main.main
和runtime.main
?,F(xiàn)在list sendToASR
試一下。
可以看到切片中增加元素時,占用了很多內(nèi)存,左右2個數(shù)據(jù)分別是flat和cum。
traces打印所有調(diào)用棧,以及調(diào)用棧的指標(biāo)信息。使用方式為traces+函數(shù)名
(模糊匹配)。
在命令行之中,還有一個重要的參數(shù) -base
,假設(shè)我們已經(jīng)通過命令行得到profile1與profile2,使用go tool pprof -base profile1 profile2
,便可以以profile1為基礎(chǔ),得出profile2在profile1之上出現(xiàn)了哪些變化。通過兩個時間切片的比較,我們可以清晰的了解到,兩個時間節(jié)點(diǎn)之中發(fā)生的變化,方便我們定位問題(很重要?。。。。?/p>
打開可視化界面的方式為:go tool pprof -http=:1234 http://localhost:8080/debug/pprof/heap
其中1234是我們指定的端口
Top
該視圖與前面所講解的 top 子命令的作用和含義是一樣的,因此不再贅述。
Graph
為函數(shù)調(diào)用圖,不在贅述.
Peek
此視圖相較于 Top 視圖,增加了所屬的上下文信息的展示,也就是函數(shù)的輸出調(diào)用者/被調(diào)用者。
Source
該視圖主要是增加了面向源代碼的追蹤和分析,可以看到其開銷主要消耗在哪里。
Flame Graph
對應(yīng)資源消耗的火焰圖,火焰圖的讀法,這里不贅述,不是本文的重點(diǎn)。
第二個下拉菜單如圖所示:
alloc_objects,alloc_space
表示應(yīng)用程序分配過的資源,不管有沒有釋放,inuse_objects,inuse_space
表示應(yīng)用程序的還未釋放的資源常配情況。
Name | Meaning |
---|---|
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) |
第一個下拉菜單可以與第二個下拉菜單相組合,可以查看臨時變量的火焰圖,常駐變量的內(nèi)存調(diào)用圖等。
tips:
程序運(yùn)行占用較大的內(nèi)存,可以通過 inuse_space 來體現(xiàn).
存在非常頻繁的 GC 活動,通常意味著 alloc_space非常高,而程序運(yùn)行過程中并沒有消耗太多的內(nèi)存(體現(xiàn)為 inuse_space 并不高),當(dāng)然也可能出現(xiàn) GC 來不及回收,因此c出現(xiàn)inuse_space 也變高的情況。這種情況下同樣會大量消耗CPU。
內(nèi)存泄漏,通常 alloc_space 較高,且
inuse_space 也較高。
上面我們已經(jīng)看完了go pprof 的所有操作,接下來講解一下go tool pprof 的具體使用流程。
通過監(jiān)控平臺監(jiān)測到內(nèi)存或cpu問題。
通過瀏覽器方式大致判斷是哪些可能的問題。
通過命令行方式抓取幾個時間點(diǎn)的profile
使用web命令查看函數(shù)調(diào)用圖
使用top 、traces、list 命令定位問題
如果出現(xiàn)了goroutine泄漏或者內(nèi)存泄漏等隨著時間持續(xù)增長的問題,go tool pprof -base
比較兩個不同時間點(diǎn)的狀態(tài)更方便我們定位問題。
啟動程序后,用瀏覽器方式打開profile:
發(fā)現(xiàn)內(nèi)存持續(xù)上升,同時goroutine也在持續(xù)上升,初步判斷,內(nèi)存泄漏是由于goroutine泄漏導(dǎo)致的。
接下來通過命令行方式抓取goroutine的情況:命令行輸入:go tool pprof localhost:8080/debug/pprof/goroutine
,獲取結(jié)果。
一、使用web命令查看調(diào)用圖,大概了解目前的goroutine的泄露情況:
通過觀察,最引入注目的便是runtime.gopark這個函數(shù),這個函數(shù)在所有g(shù)oroutine泄漏時都會出現(xiàn),并且是大頭,接下來我們研究一下這個函數(shù)的作用:
func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceEv byte, traceskip int) {
mp := acquirem()
gp := mp.curg
status := readgstatus(gp)
mp.waitlock = lock
mp.waitunlockf = unlockf
gp.waitreason = reason
mp.waittraceev = traceEv
mp.waittraceskip = traceskip
releasem(mp)
mcall(park_m)
}
該函數(shù)的作用為:
1、調(diào)用acquirem
函數(shù):獲取當(dāng)前goroutine所綁定的m,設(shè)置各類所需參數(shù)。調(diào)用 releasem
函數(shù)將當(dāng)前 goroutine 和其 m 的綁定關(guān)系解除。
2、調(diào)用 park_m
函數(shù):將當(dāng)前 goroutine 的狀態(tài)從 _Grunning 切換為 _Gwaiting,也就是等待狀態(tài)。刪除 m 和當(dāng)前 goroutine m→curg(簡稱gp)之間的關(guān)聯(lián)。
3、調(diào)用 mcall
函數(shù),僅會在需要進(jìn)行 goroutiine 切換時會被調(diào)用:切換當(dāng)前線程的堆棧,從 g 的堆棧切換到 g0 的堆棧并調(diào)用 fn(g) 函數(shù)。將 g 的當(dāng)前 PC/SP 保存在 g->sched 中,以便后續(xù)調(diào)用 goready 函數(shù)時可以恢復(fù)運(yùn)行現(xiàn)場。
綜上:該函數(shù)的關(guān)鍵作用就是將當(dāng)前的 goroutine 放入等待狀態(tài),這意味著 goroutine 被暫時被擱置了,也就是被運(yùn)行時調(diào)度器暫停了。
所以出現(xiàn)goroutine泄漏一定會調(diào)用這個函數(shù),這個函數(shù)不是goroutine泄漏的原因,而是goroutine泄漏的結(jié)果。
此外,我們發(fā)現(xiàn)有兩個函數(shù)的goroutine的達(dá)到了67,很可疑,在我們接下來的驗(yàn)證中要格外留意。
二、使用top命令,獲取更加具體的函數(shù)信息:
與上面分析的結(jié)論相似,我們要將關(guān)注點(diǎn)放在三個開啟了67個goroutine的函數(shù)。
三、traces+函數(shù)名
,查看調(diào)用棧,這一步在函數(shù)調(diào)用很復(fù)雜,無法從調(diào)用圖里面清晰的看出時使用,幫助我們更清晰的了解函數(shù)的調(diào)用堆棧:
四、使用list+函數(shù)名,查看具體代碼的問題。
通過list命令我們可以清楚的看出問題代碼是堵塞在哪里。
什么是goroutine泄漏:如果你啟動了一個 goroutine,但并沒有符合預(yù)期的退出,直到程序結(jié)束,此goroutine才退出,這種情況就是 goroutine 泄露。當(dāng) goroutine 泄露發(fā)生時,該 goroutine 的棧(一般 2k 內(nèi)存空間起)一直被占用不能釋放,goroutine 里的函數(shù)在堆上申請的空間也不能被 垃圾回收器 回收。這樣,在程序運(yùn)行期間,內(nèi)存占用持續(xù)升高,可用內(nèi)存越來也少,最終將導(dǎo)致系統(tǒng)崩潰。
什么時候出現(xiàn)goroutine泄漏:goroutine泄露一般是因?yàn)閏hannel操作阻塞而導(dǎo)致整個routine一直阻塞等待或者 goroutine 里有死循環(huán)。
具體細(xì)分一下:
從 channel 里讀,但是沒有寫。
向 unbuffered channel 寫,但是沒有讀。
向已滿的 buffered channel 寫,但是沒有讀。
select操作在所有case上阻塞。
goroutine進(jìn)入死循環(huán)中,導(dǎo)致資源一直無法釋放。
select底層也是channel實(shí)現(xiàn)的,如果所有case上的操作阻塞,select內(nèi)部的channel便會阻塞,goroutine也無法繼續(xù)執(zhí)行。所以我們使用channel時一定要格外小心。
通過分析上面兩幅圖的情況,可以判斷是因?yàn)閟elect在所有case上死鎖了,再深入代碼分析,是因?yàn)轫?xiàng)目中的的語音模型并發(fā)能力弱,在語音發(fā)包速度快起來的時候無法處理,導(dǎo)致select不滿足條件,導(dǎo)致goroutine泄漏,應(yīng)該在for循環(huán)之外加一個asr←nil
,保證func2的select一定會滿足,同時提高模型的并發(fā)能力,使得func1的不會阻塞。
防止goroutine泄漏的建議:
創(chuàng)建goroutine時就要想好該goroutine該如何結(jié)束。
使用channel時,要考慮到 channel阻塞時協(xié)程可能的行為,是否會創(chuàng)建大量的goroutine。
goroutine中不可以存在死循環(huán)。
我們通過grafana發(fā)現(xiàn)內(nèi)存出現(xiàn)泄漏:
這一次我們不使用命令行,而是使用圖形化界面來定位問題。
輸入 go tool pprof -http=:1234 localhost:8080/debug/pprof/heap
:
發(fā)現(xiàn)內(nèi)存占用很有可能是
byte.makeSlice()
導(dǎo)致的,火焰圖看的更加清晰:
而調(diào)用byte.makeSlice()
的函數(shù)為標(biāo)準(zhǔn)庫中的ioutil.ReadAll()
,接下來我們只需要研究這個標(biāo)準(zhǔn)庫函數(shù)的實(shí)現(xiàn)即可。
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
defer func() {
e := recover()
if e == nil {
return
}
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
_, err = buf.ReadFrom(r)
return buf.Bytes(), err
}
// bytes.MinRead = 512
func ReadAll(r io.Reader) ([]byte, error) {
return readAll(r, bytes.MinRead)
}
可以看到 ioutil.ReadAll
每次都會分配初始化一個大小為 bytes.MinRead 的 buffer ,bytes.MinRead 在 Golang 里是一個常量,值為 512 。就是說每次調(diào)用 ioutil.ReadAll 都先會分配一塊大小為 512 字節(jié)的內(nèi)存。
接下來看一下ReadFrom
函數(shù)的實(shí)現(xiàn):
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
if b.off >= len(b.buf) {
b.Truncate(0)
}
for {
if free := cap(b.buf) - len(b.buf); free < MinRead {
// not enough space at end
newBuf := b.buf
if b.off+free < MinRead {
// not enough space using beginning of buffer;
// double buffer capacity
newBuf = makeSlice(2*cap(b.buf) + MinRead)
}
copy(newBuf, b.buf[b.off:])
b.buf = newBuf[:len(b.buf)-b.off]
b.off = 0
}
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
b.buf = b.buf[0 : len(b.buf)+m]
n += int64(m)
if e == io.EOF {
break
}
if e != nil {
return n, e
}
}
return n, nil // err is EOF, so return nil explicitly
}
ReadFrom
函數(shù)主要作用就是從 io.Reader 里讀取的數(shù)據(jù)放入 buffer 中,如果 buffer 空間不夠,就按照每次 2x + MinRead 的算法遞增,這里 MinRead 的大小也是 512 Bytes 。
項(xiàng)目讀取的音頻文件一般很大,buffer不夠用,會一直調(diào)用makeSlice
擴(kuò)容,消耗大量內(nèi)存,但是僅僅這樣,只是程序執(zhí)行時消耗了比較多的內(nèi)存,并未有內(nèi)存泄露的情況,那服務(wù)器又是如何內(nèi)存不足的呢?這就不得不扯到 Golang 的 GC 機(jī)制。
GC算法的觸發(fā)時機(jī)
golang的GC算法為三色算法,按理說會回收臨時變量,但是觸發(fā)GC的時機(jī)導(dǎo)致了這個問題:
已分配的 Heap 到達(dá)某個閾值,會觸發(fā) GC, 該閾值由上一次 GC 時的 HeapAlloc 和 GCPercent 共同決定
每 2 分鐘會觸發(fā)一次強(qiáng)制的 GC,將未 mark 的對象釋放,但并不還給 OS
每 5 分鐘會掃描一個 Heap, 對于一直沒有被訪問的 Heap,歸還給 OS
ioutil.ReadAll
會將全部的數(shù)據(jù)加載到內(nèi)存,一個大請求會多次調(diào)用makeSlice
分配很多內(nèi)存空間,并發(fā)的時候,會在很短時間內(nèi)占用大量的系統(tǒng)內(nèi)存,然后將 GC 閾值增加到一個很高的值,這個時候要 GC 就只有等 2 分鐘一次的強(qiáng)制 GC。這樣內(nèi)存中的數(shù)據(jù)無法及時GC,同時閾值還在不停的升高,導(dǎo)致GC的效率越來越低,最終導(dǎo)致緩慢的內(nèi)存泄漏。
解決方法
//req.AduioPack,err=ioutil.ReadAll(c.Resquest.Body)
buffer:=bytes.NewBuffer(make[]byte,0,6400)
_,err:=io.Copy(buffer,c.Resquest.Body)
temp:=buffer.Bytes()
req.AduioPack=temp
不是一次性把文件讀入內(nèi)存,而是申請固定的內(nèi)存大小。
到此,關(guān)于“go pprof如何使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
網(wǎng)站標(biāo)題:gopprof如何使用
URL地址:http://chinadenli.net/article44/ppdhee.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、全網(wǎng)營銷推廣、網(wǎng)站制作、標(biāo)簽優(yōu)化、自適應(yīng)網(wǎng)站、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)