存管理--學(xué)習(xí)筆記)
Go的內(nèi)存管理內(nèi)存的分級arena區(qū)SpansGo中的mspan內(nèi)存管理組件mcachemcentralmheap內(nèi)存的分配流程內(nèi)存的分級使用的是多級分配的辦法將內(nèi)存分為多級進(jìn)行分級管理從而降低鎖的粒度。并且將可用的堆內(nèi)存采用二級管理其中每個線程會有一個自己的內(nèi)存池只有在自己的內(nèi)存池不夠時才會去全局內(nèi)存中獲取夠用時首先使用自己的內(nèi)存池。基本概念arena區(qū)arena是堆區(qū)即動態(tài)分配區(qū)域被分隔成8k大小的頁將頁組合起來稱為mspan。bitmap區(qū)域標(biāo)識arena區(qū)域的那些地址保存了對象并且使用4bit標(biāo)識對象是否包含指針、GC標(biāo)記信息。bitmap的的一個byte大小的內(nèi)存標(biāo)識的是arena的4個指針大小的內(nèi)存一個是8b因此bitmap的大小512GB/(4*8B)16GB。Spansspans中保存的是mspan是arena中分隔頁組成的基本內(nèi)存管理單元的指針每個指針對應(yīng)一頁會出現(xiàn)多個s指向同一個mspan每一個mspan中也保存了對應(yīng)的spans在回收時可以快速的找到Go中的mspanmspan是go內(nèi)存管理的基本單元是一片連續(xù)的8kb的頁組成的大塊內(nèi)存。mspan的特點mspan是包含頁的起始地址頁的span規(guī)格和頁的數(shù)量的雙端鏈表關(guān)于mspan和object的關(guān)系mspan是根據(jù)自身的SizeClass來分割成若干個object一個object可儲存一個對象在為對象分配內(nèi)存的時候mspan會分配一個和object大小接近的對象SizeClass和SpanClass的概念Size_Class Span_Class / 2由計算方式可以看出每一個Span_Class中有兩個mspan。一個分配給包含有指針的對象一個分配給不包含指針的對象。mspan和SizeClass在Go1.9中mspan的SizeClass有67種每個mspan分割的object大小是8*2n的倍數(shù)寫在代碼中// path: /usr/local/go/src/runtime/sizeclasses.go const _NumSizeClasses 67 var class_to_size [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536,1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}在使用SizeClass的時候其中為0表示大對象直接由對內(nèi)存分配小對象通過mspan來分配SizeClass也決定了mspan所能分配的頁數(shù)寫死在代碼中上圖中由兩個S指向同一個mspan這是因為兩個s指向的P同屬一個mspan因此方便了互相查找。startAddr 直接指向了arena區(qū)域表示mspan的起始地址allocBIts指向一個位圖每位代表一個塊是否被分配了對象allocCount 表示已經(jīng)分配的對象個數(shù)內(nèi)存管理組件Go中的分配器的3中組件的構(gòu)成mcachemcentralmheapmcacheGo中為每個邏輯處理器P提供一個本地線程緩存即mcache每個P同一時間只能運行一個goroutine因此訪問mcache是不需要加鎖mcache的結(jié)構(gòu)體定義//path: /usr/local/go/src/runtime/mcache.go type mcache struct { alloc [numSpanClasses]*mspan } numSpanClasses _NumSizeClasses 1mcache中使用numSpanClasses作為索引管理多個用于分配的mspan包含了所有規(guī)格的mspannumSpanClasses是mspan中介紹的_NumSizeClasses的2倍數(shù)組中的一半mspan是分配給有指針的對象一半是給沒有指針的對象。在垃圾回收的時候沒有指針的就不需要進(jìn)一步掃描了mcache的初始化在初始化時沒有mspan資源使用過程中動態(tài)的從mcentral申請會緩存起來對象小于等于32k時使用mcashe中的mspan。mcentralmecntral為mcache提供切分好的mspan資源每個mcentral保存一種特定大小的全局mspan列表分配的和未分配的mcentral被所有的工作線程共同享有存在競爭有鎖機制//path: /usr/local/go/src/runtime/mcentral.go type mcentral struct { // 互斥鎖 lock mutex // 規(guī)格 sizeclass int32 // 尚有空閑object的mspan鏈表 nonempty mSpanList // 沒有空閑object的mspan鏈表或者是已被mcache取走的msapn鏈表 empty mSpanList // 已累計分配的對象個數(shù) nmalloc uint64 }圖中的內(nèi)容和結(jié)構(gòu)體對應(yīng)獲取mspan和歸還流程獲取加鎖從nonempty鏈表找到一個可用的mspan并將其從nonempty中刪除將取出的mspan加入到empty鏈表將mspan返回給工作線程解鎖歸還加鎖將mspan從empty鏈表刪除將mspan加入到nonempty鏈表解鎖mheapmheap代表Go程序持有的所有堆空間Go程序使用一個mheap的全局對象_mheap來管理當(dāng)mcentral中沒有空閑的mspan時會向mheap申請沒有mheap時會向操作系統(tǒng)申請。mheap的主要工作大對象分配內(nèi)存管理未切割的mspan內(nèi)存的分配流程32k直接從mheap上分配16B的對象使用mcache的tiny分配器分配二者之間的首先計算對象規(guī)格然后從mcache中相應(yīng)的mspan中分配如果mcache中沒有則向mcentral申請mcentral中沒有則向mheap申請mheap中沒有則找操作系統(tǒng)。