記雜||go的內(nèi)存分配管理
本文類似于個(gè)人學(xué)習(xí)筆記不會(huì)面面俱到,需要讀者掌握一定基本知識(shí)。
先從span講起,span是go內(nèi)存的最小管理單位,最小存儲(chǔ)單位page為8KB,span便是page的整數(shù)倍大小,從8B到32KB共67個(gè)等級(jí)+0級(jí)(我所學(xué)習(xí)的教材寫(xiě)成了67種,后來(lái)發(fā)現(xiàn)他寫(xiě)錯(cuò)了,源碼部分在runtime/sizeclasses.go 內(nèi)有詳細(xì)數(shù)據(jù)),其中0級(jí)代表大小不確定的等級(jí)。span的大小和等級(jí)并不相同,比如class1 span為8B而span的大小為8KB,也就是說(shuō)能裝下1024個(gè)大小為8B的對(duì)象。接下來(lái)的內(nèi)容便圍繞著span展開(kāi):
go使用了一種現(xiàn)代化的內(nèi)存分配算法TCMalloc,在此基礎(chǔ)上進(jìn)行了三級(jí)管理:mcache,mcentral,mheap。
- mcache:中內(nèi)含 (67種span+1)*(有無(wú)指針2種,GC時(shí)使用) 共136個(gè)span,span為每個(gè)P獨(dú)占,由于P上只會(huì)有一個(gè)G在運(yùn)行所以無(wú)需加鎖,同時(shí)也意味著mcache的數(shù)量和P相等(注:在初始化時(shí)并沒(méi)有任何span而是在使用時(shí)向mcentral申請(qǐng)并緩存)。
- mcentral:為鏈表結(jié)構(gòu)共 兩條(空閑列表和無(wú)空閑)*67種 每一級(jí)別的span各有一個(gè)對(duì)應(yīng)的mcentral,mcentral內(nèi)span的數(shù)量并不固定,如果不夠用了則會(huì)向mheap申請(qǐng),全局P共享。
- mheap:全局內(nèi)存池,便是go運(yùn)行時(shí)向操作系統(tǒng)申請(qǐng)的一大塊內(nèi)存,這里你可能有個(gè)誤區(qū),棧在什么地方分配內(nèi)存?沒(méi)錯(cuò)也在mheap,與java不同,棧的內(nèi)存也是分配在堆上的。
為什么要這么分?先看go是怎么為對(duì)象分配內(nèi)存的,go的對(duì)象分為了3種:微小對(duì)象<16B,16B<小對(duì)象<32KB,大對(duì)象>32KB。這里微小對(duì)象和小對(duì)象在span中便有足夠大的空間分配,所以分配在mcahe中,其中微小對(duì)象會(huì)放在span的class 2(16B)中,根據(jù)2,4,8規(guī)則進(jìn)行字節(jié)對(duì)齊,這是一種優(yōu)化手段可以有效減少堆大小,甚至8B的對(duì)象并不會(huì)放在class 1中,優(yōu)先把2*8B放在class 2中以減少位圖等用于記錄的數(shù)據(jù)。而mcache中如果span滿了,便會(huì)去向?qū)?yīng)mcentral中申請(qǐng)(加鎖)(2條鏈表都遍歷,因?yàn)橛捎贕C無(wú)法保證無(wú)空閑鏈表中是否已經(jīng)出現(xiàn)了空閑的)新的span,而原來(lái)的會(huì)標(biāo)記為空閑,放在mcentral的空閑列表中等待GC,如果mcentral也沒(méi)有可用的了,便會(huì)向mheap申請(qǐng)(全局鎖)。而大對(duì)象便直接在mheap中進(jìn)行內(nèi)存分配。
~飛天大糙
Lotalot你干了什么?!沒(méi)有g(shù)olang八股文我們?nèi)绾慰购怆p招,Lotalot淡笑一聲:“很簡(jiǎn)單,我自己寫(xiě)不就是了”說(shuō)完,他氣息終于不再掩飾,顯露而出,Go八股文小解!