W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎勵
大家好,我是V 哥。GO GO GO,今天來說一說Go語言內(nèi)存分配問題,Go語言內(nèi)存分配的源碼主要集中在runtime
包中,它實(shí)現(xiàn)了Go語言的內(nèi)存管理,包括初始化、分配、回收和釋放等。下面來對這些過程詳細(xì)分析一下,先贊后看,絕不擺爛:
源碼位置: runtime/malloc.go
mheap
初始化:
mheap
是整個Go運(yùn)行時的核心內(nèi)存分配結(jié)構(gòu),用于管理大塊內(nèi)存。sysAlloc
分配給mheap
。 func mallocinit() {
mheap_.init() // 初始化全局mheap_
}
mcache
初始化:
mcache
,用來緩存小塊內(nèi)存分配,減少鎖競爭。mcache
由mheap
分配,存儲小塊內(nèi)存(≤32KB)。 func allocmcache() *mcache {
c := new(mcache)
c.refill() // 預(yù)填充小內(nèi)存塊
return c
}
Go的內(nèi)存分配分為以下幾種場景:
mcache
中的內(nèi)存。mcache
按大小類(class)分配,這些類通過sizeclasses
數(shù)組定義。mcache.alloc
,如果mcache中沒有可用的內(nèi)存塊,會從mheap
中拉取。 func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
if size <= maxSmallSize {
// 小對象分配
c := getmcache() // 獲取當(dāng)前P的mcache
s := c.alloc(size, needzero)
return s
}
}
mheap
中分配大塊內(nèi)存。span
(連續(xù)內(nèi)存塊)管理這些大塊內(nèi)存。 func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
if size > maxSmallSize {
// 大對象分配
s := mheap_.allocSpan(size)
return s
}
}
源碼位置: runtime/mgc.go
Go的垃圾回收器使用三色標(biāo)記清除算法,主要分以下幾個階段:
mcache
或mheap
。 func gcSweep() {
// 遍歷所有span,清理未使用的對象
for _, s := range mheap_.spans {
s.sweep()
}
}
源碼位置: runtime/malloc.go
Go會主動將不再使用的大塊內(nèi)存返還給操作系統(tǒng),調(diào)用sysUnused
或sysFree
實(shí)現(xiàn)。
mcache
。mcache
滿了,釋放到mheap
。mheap
。mheap
中內(nèi)存長時間未使用,釋放給操作系統(tǒng)。mcache
中直接獲取。Go的內(nèi)存分配機(jī)制結(jié)合了現(xiàn)代內(nèi)存分配的多種優(yōu)化技術(shù),能夠高效地處理并發(fā)場景。關(guān)鍵點(diǎn)在于:
mcache
優(yōu)化分配速度。mheap
管理,提高內(nèi)存利用率。
深入分析 Go 內(nèi)存管理中核心模塊 mcache
和 mheap
的代碼實(shí)現(xiàn),可以更好地理解它們的協(xié)同工作方式。以下是詳細(xì)的源碼分析:
mcache
是每個 P (邏輯處理器) 的本地內(nèi)存緩存,目的是減少對全局堆的鎖爭用。
它的源碼定義在 runtime/mcache.go
。
type mcache struct {
alloc [numSpanClasses]*mspan // 每個 size class 分配一個 span
tiny uintptr // 小對象分配緩存
tinyoffset uintptr // tiny 的當(dāng)前偏移量
local_nlookup uintptr // 本地分配次數(shù)
...
}
字段解釋:
alloc
:
size class
分類。tiny
和 tinyoffset
:
mallocgc
)。local_nlookup
:
mcache.alloc
)
當(dāng)分配小對象時,調(diào)用 alloc
方法從 mcache
中獲取內(nèi)存:
func (c *mcache) alloc(size uintptr, needzero bool) unsafe.Pointer {
sc := sizeToClass(size) // 根據(jù) size 找到對應(yīng)的 size class
s := c.alloc[sc]
if s == nil || s.freeindex == s.nelems {
// 當(dāng)前緩存中沒有可用的 span,從 mheap 中獲取
s = mheap_.allocSpan(sc)
if s == nil {
throw("out of memory")
}
c.alloc[sc] = s
}
...
return obj
}
工作流程:
size
計(jì)算 size class
。span
:
span
有空閑塊,從 freeindex
取一個。span
已滿,從 mheap
中分配新的 span。mcache.releaseAll
)
當(dāng) GC 發(fā)生時,mcache
會將所有未使用的 spans 返還給 mheap
。
func (c *mcache) releaseAll() {
for i := range c.alloc {
s := c.alloc[i]
if s != nil {
mheap_.freeSpan(s) // 釋放到 mheap
c.alloc[i] = nil
}
}
}
mheap
是全局的堆管理器,負(fù)責(zé)分配和回收大塊內(nèi)存(span),以及為 mcache
提供支持。它的源碼定義在 runtime/mheap.go
。
type mheap struct {
spans []*mspan // 全局管理的 spans
freelist [numSpanClasses]*mspan // 每個 size class 的空閑列表
arenas [maxArenas]*heapArena // 內(nèi)存分配的區(qū)域
lock mutex // 全局鎖
...
}
字段解釋:
spans
:
freelist
:
size class
的空閑 span 鏈表。arenas
:
lock
:
mheap.allocSpan
)
當(dāng) mcache
需要新的 span 時,會調(diào)用 mheap.allocSpan
:
func (h *mheap) allocSpan(sc spanClass) *mspan {
lock(&h.lock) // 加鎖,防止并發(fā)沖突
s := h.freelist[sc]
if s != nil {
h.freelist[sc] = s.next // 從 freelist 獲取 span
unlock(&h.lock)
return s
}
...
unlock(&h.lock)
return h.grow(sc) // freelist 沒有時,從 arenas 擴(kuò)展
}
工作流程:
freelist
中取出一個空閑的 span。freelist
為空,調(diào)用 grow
方法,從 arenas
分配新的 span。mheap.freeSpan
)
當(dāng) mcache
或垃圾回收器釋放內(nèi)存時,調(diào)用 mheap.freeSpan
:
func (h *mheap) freeSpan(s *mspan) {
lock(&h.lock) // 加鎖
sc := s.spanclass()
s.reset() // 重置 span 狀態(tài)
s.next = h.freelist[sc]
h.freelist[sc] = s // 回收到 freelist
unlock(&h.lock)
}
工作流程:
spanclass
確定 span 類型。freelist
鏈表。mheap.grow
)
當(dāng) freelist
無法滿足分配請求時,從底層 arenas
分配新的 span:
func (h *mheap) grow(sc spanClass) *mspan {
p := sysAlloc(_PageSize * npage, &memstats.heap_sys) // 從操作系統(tǒng)分配物理內(nèi)存
if p == nil {
throw("out of memory")
}
s := newMSpan() // 創(chuàng)建新的 span
s.init(p, npage)
...
return s
}
mcache
中分配。mheap
分配。mcache
釋放的內(nèi)存會回收到 mheap
,進(jìn)入 freelist
。mcache.releaseAll
和 mheap.freeSpan
釋放無用的 span。mcache
是每個 P (邏輯處理器) 的本地緩存,優(yōu)化小對象分配的性能。mheap
是全局堆管理器,負(fù)責(zé)大對象分配和全局內(nèi)存回收。span
的共享和回收機(jī)制協(xié)作,兼顧性能與內(nèi)存利用率。關(guān)注威哥愛編程,成長路上一起努力,點(diǎn)個贊再走唄。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: