Golang的內(nèi)存分配與GC

原文: GO內(nèi)存分配與GC

Thread-Caching Malloc

TCMalloc是谷歌公開的一種內(nèi)存管理與分配的方式耕皮,它的特點(diǎn)是能在本地快速分配某些對(duì)象同波,降低對(duì)共享內(nèi)存的訪問(wèn)空骚,從而降低內(nèi)存分配過(guò)程中對(duì)鎖的競(jìng)爭(zhēng)巷送,提升內(nèi)存分配效率

Golang的內(nèi)存分配是基于TCMalloc模型實(shí)現(xiàn)的驶忌,理解TCMalloc對(duì)理解Golang內(nèi)存分配至關(guān)重要,這里簡(jiǎn)要說(shuō)明一下TCMalloc的內(nèi)存分配機(jī)制

Page與Span

TCMalloc中笑跛,內(nèi)存以Span(跨度)進(jìn)行管理付魔,每個(gè)Span包含1個(gè)到多個(gè)Page頁(yè),Page是內(nèi)存的最基本單位飞蹂,每個(gè)Page的大小為4KB

小對(duì)象與大對(duì)象

TCMalloc中几苍,將尺寸小于等于32KB的對(duì)象稱為小對(duì)象,對(duì)于尺寸大于32KB的對(duì)象稱為大對(duì)象陈哑,它們有不同的分配方式

小對(duì)象在分配內(nèi)存時(shí)會(huì)將一個(gè)Page頁(yè)進(jìn)行切割以存儲(chǔ)多個(gè)對(duì)象妻坝,例如用于存儲(chǔ)8Bytes的小對(duì)象的數(shù)據(jù)頁(yè),它將切割出512個(gè)存儲(chǔ)區(qū)

大對(duì)象在存儲(chǔ)時(shí)以頁(yè)面對(duì)齊并且占據(jù)整數(shù)的頁(yè)惊窖,一個(gè)33KB的對(duì)象在存儲(chǔ)時(shí)它會(huì)占用9個(gè)數(shù)據(jù)頁(yè)

在TCMalloc模型中刽宪,內(nèi)存的分配管理有三種模型,以下分別介紹

ThreadCache

第一種是ThreadCache也即線程本地緩存界酒,該緩存適用于一些固定尺寸的對(duì)象分配

ThreadCache以一個(gè)固定的映射關(guān)系分配不同大小的對(duì)象圣拄,每個(gè)大小的級(jí)別稱為一個(gè)Class,在TCMalloc的相關(guān)介紹中并未找到對(duì)Class映射表的約定毁欣,這里需要找源碼去分析了庇谆,以后補(bǔ)充岳掐,不過(guò)據(jù)介紹,大約存在170余個(gè)的不同Class

對(duì)象的大小基本遵循以下規(guī)則: 以存儲(chǔ)8Bytes最小對(duì)象的Class為起始饭耳,每個(gè)Class比前一個(gè)Class存儲(chǔ)的對(duì)象大小按照8B串述、16B、32B寞肖、64B等等的間隔遞增剖煌,最大的間隔為256B,例如下表簡(jiǎn)要介紹了遞增關(guān)系

Class級(jí)別 Bytes大小 單個(gè)Page可分配的數(shù)量 尾部浪費(fèi)的Bytes
1 8 512 0
2 16 256 0
3 24 170 16
4 32 128 0
5 48 85 16
6 64 64 0
... ... ... ...

所有的Class以該Class的級(jí)別編號(hào)作為索引保存在一個(gè)List中逝淹,每個(gè)Class都是一個(gè)Span的鏈表耕姊,鏈表中每個(gè)Span根據(jù)Class的級(jí)別會(huì)存儲(chǔ)不同數(shù)量的Page頁(yè),并將這些頁(yè)的總內(nèi)存切分為該Class對(duì)應(yīng)的大小的對(duì)象

分配時(shí)將待分配的對(duì)象大小與映射表對(duì)齊栅葡,找到需要的Class后從該Class的鏈表中彈出表頭節(jié)點(diǎn)進(jìn)行存儲(chǔ)茉兰,然后將該對(duì)象從鏈表的頭部刪除,在釋放一個(gè)對(duì)象時(shí)欣簇,將該內(nèi)存對(duì)象加入到該Class的表尾

當(dāng)ThreadCache中某個(gè)Class的空閑空間不足時(shí)规脸,將會(huì)向CenterCache批量申請(qǐng)新的內(nèi)存加入到該Class的空閑鏈表中,當(dāng)某個(gè)Class的空閑內(nèi)存超出了預(yù)訂大小(2MB)時(shí)熊咽,將會(huì)通過(guò)垃圾搜集器將多于的空閑內(nèi)存歸還到CenterCache中

在此ThreadCache中莫鸭,內(nèi)存的分配都是發(fā)生在每個(gè)線程的內(nèi)部,因此這些內(nèi)存的訪問(wèn)不需要加鎖横殴,也是內(nèi)存分配速度最快的

CenterCache

第二種是CenterCache也即全局中心緩存被因,該緩存與ThreadCache一樣僅適用于一些固定Class的對(duì)象分配,不過(guò)該緩存是全局的衫仑,對(duì)該緩存的訪問(wèn)需要加鎖

當(dāng)ThreadCache本地的存儲(chǔ)空間不足以分配新的內(nèi)存時(shí)梨与,將對(duì)CenterCache加鎖,然后從CenterCache中批量獲取該尺寸的一批連續(xù)的內(nèi)存到ThreadCache中文狱,然后繼續(xù)分配本地內(nèi)存的分配過(guò)程

當(dāng)CenterCache中空閑內(nèi)存不足時(shí)粥鞋,將向PageHeap申請(qǐng)新的空閑內(nèi)存,并切割為需要的尺寸存放到空閑空間中

釋放時(shí)也是通過(guò)批量的方式將空閑內(nèi)存歸還到PageHeap中瞄崇,內(nèi)存的釋放歸還由垃圾收集器負(fù)責(zé)

PageHeap

第三種是PageHeap也即頁(yè)堆呻粹,該緩存是全局的,對(duì)PageHeap的訪問(wèn)需要加鎖苏研,PageHeap管理著整個(gè)程序的全部?jī)?nèi)存

PageHeap對(duì)內(nèi)存的管理方式與ThreadCache類似昂利,其以Page的頁(yè)數(shù)為索引保存在一個(gè)List中森缠,List中每個(gè)索引存儲(chǔ)的是一個(gè)Span的鏈表吓坚,每個(gè)Span保存了對(duì)應(yīng)的頁(yè)數(shù)瞧栗,例如索引為1的Span鏈表中,每個(gè)Span包含一個(gè)Page,索引為2的Span鏈表中庄萎,每個(gè)Span包含兩個(gè)Page踪少,以此類推,最大的連續(xù)Page為255個(gè)(沒有包含0個(gè)Page的Span鏈表糠涛,所以List的0號(hào)索引不用援奢,List最多為256個(gè)元素,因此最大的連續(xù)頁(yè)數(shù)為255)

所有的大對(duì)象分配將會(huì)直接分配在PageHeap中忍捡,分配時(shí)計(jì)算該對(duì)象使用的頁(yè)數(shù)然后從對(duì)應(yīng)的Span鏈表中取出一個(gè)Span返回給程序進(jìn)行內(nèi)存分配

PageHeap的內(nèi)存由垃圾收集器進(jìn)行管理

垃圾收集

當(dāng)ThreadCache中的緩存大小達(dá)到閥值時(shí)(默認(rèn)為2MB)將對(duì)該緩存執(zhí)行垃圾清理集漾,該閥值會(huì)隨著線程數(shù)量的增多而下降,以免在大量線程的情況下浪費(fèi)內(nèi)存

在進(jìn)行垃圾收集時(shí)將會(huì)根據(jù)ThreadCache的歷史內(nèi)存操作簡(jiǎn)單測(cè)算未來(lái)可能出現(xiàn)的內(nèi)存訪問(wèn)情況砸脊,對(duì)不同的Class執(zhí)行不同的管理具篇,從未用到的Class空閑空間將會(huì)被回收放入CenterCache中以供其他線程使用,經(jīng)常分配和釋放的Class將會(huì)保留更長(zhǎng)的空閑鏈表以避免過(guò)多的對(duì)CenterCache進(jìn)行訪問(wèn)

Golang內(nèi)存管理與GC(Ver: 1.17)

Golang中的內(nèi)存管理基于TCMalloc模型凌埂,因此其管理單位與TCMalloc模型一致驱显,都使用Page與Span的概念進(jìn)行管理,因此理解TCMalloc模型也就基本理解了Golang的內(nèi)存管理模式瞳抓,具體的差異不過(guò)是對(duì)一些概念的微調(diào)以及具體實(shí)現(xiàn)過(guò)程中客制化的內(nèi)容埃疫,以下介紹在Golang中有區(qū)別的地方

微對(duì)象、小對(duì)象與大對(duì)象

在Golang中孩哑,對(duì)象的分配更進(jìn)一步細(xì)分為微對(duì)象栓霜、小對(duì)象以及大對(duì)象

將不含有指針且大小小于16Byte的對(duì)象稱為微對(duì)象
大小小于等于32KB且不屬于微對(duì)象的對(duì)象稱為小對(duì)象
大于32KB的對(duì)象稱為大對(duì)象

微對(duì)象大小的選擇并不是最小的8Bytes,選擇16是有意義的横蜒,在runtime/malloc.go:987有對(duì)此的注釋描述

Tiny allocator.

Tiny allocator combines several tiny allocation requests into a single memory block. The resulting memory block is freed when all subobjects are unreachable. The subobjects must be noscan (don't have pointers), this ensures that the amount of potentially wasted memory is bounded.

Size of the memory block used for combining (maxTinySize) is tunable.
Current setting is 16 bytes, which relates to 2x worst case memory wastage (when all but one subobjects are unreachable).
8 bytes would result in no wastage at all, but provides less opportunities for combining.
32 bytes provides more opportunities for combining, but can lead to 4x worst case wastage.
The best case winning is 8x regardless of block size.

Objects obtained from tiny allocator must not be freed explicitly.
So when an object will be freed explicitly, we ensure that its size >= maxTinySize.

SetFinalizer has a special case for objects potentially coming from tiny allocator, it such case it allows to set finalizers for an inner byte of a memory block.

The main targets of tiny allocator are small strings and standalone escaping variables. On a json benchmark the allocator reduces number of allocations by ~12% and reduces heap size by ~20%.

小對(duì)象的映射表

Golang中對(duì)于小對(duì)象的Class有明確的映射胳蛮,這里做一下簡(jiǎn)要的介紹,完整的映射表見runtime/sizeclasses.go

Class(級(jí)別) Bytes(每個(gè)對(duì)象) Bytes(Span大小) 包含的對(duì)象數(shù)量 末尾浪費(fèi)的字節(jié)大小 最多會(huì)產(chǎn)生多少浪費(fèi)
1 8 8192 1024 0 87.5%
2 16 8192 512 0 43.75%
3 24 8192 341 8 29.24%
4 32 8192 256 0 21.88%
5 48 8192 170 32 31.52%
... ... ... ... ... ...
18 256 8192 32 0 5.86%
19 288 8192 28 128 12.16%
... ... ... ... ... ...
35 1408 16384 11 896 14.00%
... ... ... ... ... ...
67 32768 32768 1 0 12.50%

微對(duì)象與小對(duì)象的內(nèi)存分配

微對(duì)象與小對(duì)象的分配都是在ThreadCache上愁铺,ThreadCache在Golang中對(duì)應(yīng)的是mcache結(jié)構(gòu)體鹰霍,其定義在runtime/mcache.go

mcache結(jié)構(gòu)體維護(hù)了136(索引0-67一共68個(gè)乘以2)個(gè)Class的數(shù)組,這里數(shù)組的數(shù)量是Class級(jí)別數(shù)量的兩倍

這是因?yàn)樵贕olang中茵乱,每個(gè)級(jí)別都有兩個(gè)Span列表用于存儲(chǔ),有指針與無(wú)指針的小對(duì)象是分別存儲(chǔ)的孟岛,計(jì)算時(shí)將該Class級(jí)別索引位置向左移一位(乘2)瓶竭,然后如果不含指針將其與1做位或運(yùn)算(加1),例如級(jí)別為67的Class渠羞,在獲取Span鏈表時(shí)斤贰,其Class宿主中的位置為(67<<1)|int(noscan)mcache結(jié)構(gòu)中還維護(hù)了內(nèi)存分配的狀態(tài)與統(tǒng)計(jì)信息

微對(duì)象不含指針次询,在分配時(shí)固定使用一個(gè)Span列表來(lái)進(jìn)行內(nèi)存分配操作荧恍,其索引是tinySpanClass常量(當(dāng)前是5,也就是Class級(jí)別為2且不含指針)指定的,mcache結(jié)構(gòu)中維護(hù)了當(dāng)前獲取的Span塊中已分配的對(duì)象偏移量送巡,微對(duì)象分配時(shí)首先對(duì)已分配的Span塊偏移量進(jìn)行向上對(duì)齊摹菠,以確保之后分配的內(nèi)存都是對(duì)齊的

然后會(huì)檢查即將分配的大小與當(dāng)前偏移量相加是否大于微對(duì)象內(nèi)存塊的上限,也就是16Bytes骗爆,如果是那么獲取一個(gè)新的塊來(lái)進(jìn)行分配并更新mcache的統(tǒng)計(jì)信息次氨,否則將在已有的數(shù)據(jù)塊上進(jìn)行對(duì)象的內(nèi)存分配,然后更新mcache的統(tǒng)計(jì)信息

小對(duì)象的分配則直接對(duì)分配的內(nèi)存大小向上對(duì)齊并計(jì)算其所屬的Class摘投,通過(guò)size_to_class8size_to_class128來(lái)獲取該對(duì)象大小對(duì)應(yīng)的Class級(jí)別煮寡,然后會(huì)根據(jù)該對(duì)象是否含有指針來(lái)計(jì)算該Class的索引位置

大對(duì)象的內(nèi)存分配

由上邊小對(duì)象的分配可知,最小級(jí)別的小對(duì)象在分配時(shí)犀呼,對(duì)應(yīng)的Class列表索引最小是2(Class級(jí)別為1的索引為1幸撕,計(jì)算時(shí)為1 << 1 | int(noscan))

因此Class列表的前兩個(gè)索引被用來(lái)作為大對(duì)象分配時(shí)的Span鏈表,mcache在分配大對(duì)象時(shí)根據(jù)是否含有指針將其索引映射為Class列表中0或1的Span鏈表

并直接從PageHeap也即Golang中的mheap上直接分配內(nèi)存外臂,不過(guò)這里分配內(nèi)存之后并不是將分配的Span加入到mcache的Class列表中杈帐,而是直接加入到CenterCache也即Golang中的mcenter中對(duì)應(yīng)Class級(jí)別的Span列表中,以便垃圾收集期間對(duì)齊進(jìn)行垃圾清理

GC原理

垃圾收集涉及的內(nèi)容是方方面面的专钉,其貫穿程序的整個(gè)生命周期以及所有與內(nèi)存相關(guān)聯(lián)的組件挑童,以下僅整理Golang中垃圾收集的過(guò)程,不涉及GC的具體實(shí)現(xiàn)代碼跃须,關(guān)于實(shí)現(xiàn)以后再單獨(dú)寫文章進(jìn)行記錄

Golang的垃圾收集器是逐漸演進(jìn)的站叼,這里不對(duì)歷史進(jìn)行追溯,在當(dāng)前版本菇民,垃圾收集器使用三色標(biāo)記法尽楔,并且通過(guò)混合寫屏障(插入與刪除)來(lái)保證并發(fā)垃圾收集的性能與內(nèi)存安全性

對(duì)于三色標(biāo)記法以及寫屏障技術(shù)這里不進(jìn)行展開,對(duì)此進(jìn)行介紹的文章很多第练,這里僅研究Golang的GC觸發(fā)時(shí)機(jī)阔馋、各種階段的任務(wù)、GC時(shí)的內(nèi)存分配等等

其基本過(guò)程是啟動(dòng)GC時(shí)進(jìn)行一些狀態(tài)檢查以及準(zhǔn)備工作娇掏,然后開始與用戶程序并行執(zhí)行進(jìn)行內(nèi)存狀態(tài)的標(biāo)記呕寝,標(biāo)記過(guò)程中會(huì)打開內(nèi)存屏障,以保證新創(chuàng)建的對(duì)象不會(huì)被錯(cuò)誤的清理婴梧,當(dāng)標(biāo)記完成后進(jìn)入清理階段下梢,該階段與用戶程序并行

在Golang的GC過(guò)程中會(huì)觸發(fā)兩次STW,均發(fā)生在GC狀態(tài)變更的時(shí)候

GC的觸發(fā)時(shí)機(jī)

Golang中在以下情況會(huì)觸發(fā)GC測(cè)試塞蹭,測(cè)試的條件有三種類型

  • 堆內(nèi)存大小測(cè)試(若當(dāng)前堆活動(dòng)內(nèi)存大于等于上次GC時(shí)控制器計(jì)算的控制大小)
  • 時(shí)間測(cè)試(若最后一次GC時(shí)間距離上一次GC已經(jīng)經(jīng)過(guò)設(shè)定時(shí)間孽江,默認(rèn)時(shí)間為2分鐘)
  • GC周期數(shù)測(cè)試(若新開始的周期數(shù)大于當(dāng)前已經(jīng)進(jìn)行的周期數(shù))

測(cè)試時(shí)選擇一種條件進(jìn)行測(cè)試,若條件滿足則啟動(dòng)新一輪的GC番电,在以下幾種情況中會(huì)進(jìn)行GC測(cè)試

  • 在處理新的微岗屏、小對(duì)象內(nèi)存分配請(qǐng)求時(shí),若mcache內(nèi)存不足,向mcenter申請(qǐng)新的內(nèi)存時(shí)这刷,會(huì)觸發(fā)GC測(cè)試婉烟,該測(cè)試的條件是堆內(nèi)存大小測(cè)試
  • 在處理新的大對(duì)象內(nèi)存分配請(qǐng)求時(shí),一定會(huì)觸發(fā)GC測(cè)試崭歧,測(cè)試條件是堆內(nèi)存大小測(cè)試
  • Golang的系統(tǒng)監(jiān)控線程會(huì)檢查系統(tǒng)的狀態(tài)隅很,嘗試進(jìn)行GC,該測(cè)試條件是時(shí)間測(cè)試

另外用戶可以還可以通過(guò)runtime.GC函數(shù)主動(dòng)發(fā)起一次GC率碾,該情況會(huì)強(qiáng)制啟動(dòng)GC(通過(guò)將開始的GC周期數(shù)+1)叔营,啟動(dòng)時(shí)若已在GC過(guò)程中,將中斷該GC過(guò)程并開始一輪新的GC

GC的各個(gè)階段以及階段任務(wù)

Golang中GC有三種狀態(tài)所宰,可以分為四個(gè)階段任務(wù)绒尊,狀態(tài)有下列三種

  • _GCoff該狀態(tài)GC沒有在運(yùn)行,此狀態(tài)下寫屏障沒有開啟
  • _GCmark 該狀態(tài)GC正在執(zhí)行標(biāo)記工作仔粥,此狀態(tài)下寫屏障會(huì)被開啟
  • _GCmarktermination 該狀態(tài)GC正在執(zhí)行標(biāo)記工作婴谱,此狀態(tài)寫寫屏障會(huì)被開啟,程序會(huì)進(jìn)入STW

由三種狀態(tài)的切換可以將GC分為四個(gè)階段任務(wù)

首先是啟動(dòng)階段躯泰,該階段GC狀態(tài)為_GCoff谭羔,在啟動(dòng)階段將會(huì)進(jìn)行一些GC啟動(dòng)前的準(zhǔn)備工作,包括:

  • 當(dāng)前處理器P與協(xié)程G是否滿足一些條件麦向,判定的條件還未細(xì)看瘟裸,待補(bǔ)充
  • 獲取GC需要的鎖,并在獲取鎖后再次檢查是否滿足GC啟動(dòng)條件诵竭,若不滿足則結(jié)束本次GC
  • 檢查所有處理器P的mcache的延遲刷新緩存是否已經(jīng)刷新话告,該檢查屬于狀態(tài)一致性檢查,若系統(tǒng)內(nèi)狀態(tài)不滿足要求那么程序直接通過(guò)panic結(jié)束
  • 創(chuàng)建出用于執(zhí)行GC掃描的協(xié)程G卵慰,但此時(shí)這些G不會(huì)被啟動(dòng)沙郭,會(huì)在掃描階段啟動(dòng)
  • 重置系統(tǒng)狀態(tài): 重置所有G的GC狀態(tài)、重置堆內(nèi)存的標(biāo)記掃描狀態(tài)裳朋、重置GC工作的一些狀態(tài)
  • 進(jìn)入STW
  • 將GC狀態(tài)更改為_GCmark病线,開啟內(nèi)存屏障,掃描所有的根對(duì)象并標(biāo)記再扭,將所有微對(duì)象標(biāo)記為黑色
  • 恢復(fù)STW
  • 釋放鎖

第二個(gè)階段是后臺(tái)標(biāo)記階段氧苍,后臺(tái)標(biāo)記階段將在STW恢復(fù)后開始,此時(shí)標(biāo)記掃描工作將與程序并行執(zhí)行泛范,上一個(gè)階段創(chuàng)建的用于后臺(tái)處理標(biāo)記的G會(huì)被喚醒,內(nèi)存的標(biāo)記工作將由這些G來(lái)執(zhí)行

后臺(tái)標(biāo)記的任務(wù)數(shù)量與GOMAXPROC的數(shù)量相等紊撕,但并非所有的處理器P都會(huì)被用于執(zhí)行標(biāo)記任務(wù)罢荡,可用于執(zhí)行標(biāo)記任務(wù)的處理器數(shù)量是全部處理器數(shù)量的一定比例,其默認(rèn)為百分之25,若開啟了debug模式則其數(shù)值等于GOMAXPROC区赵,在計(jì)算專用處理器P的數(shù)量時(shí)會(huì)進(jìn)行四舍五入的取整操作惭缰,若GC處理時(shí)的性能分?jǐn)?shù)仍然達(dá)不到百分之25的要求,那么會(huì)臨時(shí)征用其他的處理器P處理標(biāo)記工作

對(duì)于標(biāo)記任務(wù)的調(diào)度要優(yōu)先于其他任務(wù)笼才,其過(guò)程是在創(chuàng)建后臺(tái)標(biāo)記任務(wù)時(shí)漱受,標(biāo)記任務(wù)將自己加入到后臺(tái)標(biāo)記工作池中,之后自身進(jìn)入休眠等待喚醒骡送,調(diào)度器在調(diào)度其他任務(wù)之前將會(huì)檢查當(dāng)前是否在后臺(tái)標(biāo)記階段昂羡,如果是那么檢查是否有未被調(diào)度執(zhí)行的標(biāo)記任務(wù)以及當(dāng)前允許用于處理標(biāo)記任務(wù)的處理器P數(shù)量是否滿足條件,若有則喚醒該任務(wù)摔踱,否則處理用戶程序任務(wù)虐先,后臺(tái)標(biāo)記任務(wù)在執(zhí)行時(shí)是不可搶占的

標(biāo)記完成后進(jìn)入第三個(gè)階段,標(biāo)記終止階段派敷,在該階段會(huì)刷新所有處理器的寫屏障緩沖蛹批,然后切換GC狀態(tài),主要流程如下:

  • 獲取GC需要的鎖
  • 確認(rèn)所有標(biāo)記工作已完成篮愉,若有未完成的任務(wù)則繼續(xù)處理
  • 刷新所有處理器P的寫屏障緩存腐芍,并再次確認(rèn)是否所有標(biāo)記工作已完成
  • 進(jìn)入STW
  • 再次刷新所有處理器的寫屏障緩存
  • 若需要重新恢復(fù)STW則恢復(fù)STW并重新進(jìn)入標(biāo)記終止階段
  • 切換GC狀態(tài)為_GCmarktermination
  • 堆棧的標(biāo)記、統(tǒng)計(jì)试躏、操作等猪勇,這里還沒有仔細(xì)研究,以后補(bǔ)充
  • 切換GC狀態(tài)為_GCoff冗酿,關(guān)閉內(nèi)存屏障
  • GC內(nèi)部狀態(tài)的統(tǒng)計(jì)工作
  • 恢復(fù)STW
  • 釋放鎖

之后進(jìn)入最后的階段埠对,并行清理階段,該階段將會(huì)對(duì)之前標(biāo)記的所有白色內(nèi)容執(zhí)行清理裁替,然后釋放堆棧內(nèi)存项玛,內(nèi)存的清理工作是與用戶程序并行執(zhí)行的,并且必須在下一次GC之前完成

GC時(shí)調(diào)度器與內(nèi)存分配的輔助工作

在GC的第二個(gè)階段中弱判,用戶程序的內(nèi)存分配與后臺(tái)標(biāo)記工作將并行執(zhí)行襟沮,若某個(gè)G的內(nèi)存分配速度過(guò)快,可能會(huì)導(dǎo)致GC的速度無(wú)法跟上新內(nèi)存增長(zhǎng)的速度昌腰,因此在GC開始時(shí)开伏,將會(huì)為所有用戶程序的G分配一個(gè)分?jǐn)?shù),若該分?jǐn)?shù)為負(fù)數(shù)遭商,則此G需要協(xié)助GC進(jìn)行標(biāo)記工作以賺取足夠的分?jǐn)?shù)值固灵,此時(shí)該協(xié)助工作是可以被搶占的,若GC狀態(tài)不為_GCoff劫流,那么內(nèi)存分配器還會(huì)在內(nèi)存分配完成后直接將該內(nèi)存標(biāo)記為黑色

在后臺(tái)標(biāo)記階段巫玻,若標(biāo)記任務(wù)的數(shù)量以及足夠丛忆,但是當(dāng)前P空閑,此時(shí)也會(huì)協(xié)助進(jìn)行標(biāo)記仍秤,此任務(wù)也是可以被搶占的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末熄诡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子诗力,更是在濱河造成了極大的恐慌凰浮,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苇本,死亡現(xiàn)場(chǎng)離奇詭異袜茧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)圈澈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門惫周,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人康栈,你說(shuō)我怎么就攤上這事递递。” “怎么了啥么?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵登舞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我悬荣,道長(zhǎng)菠秒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任氯迂,我火速辦了婚禮践叠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嚼蚀。我一直安慰自己禁灼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布轿曙。 她就那樣靜靜地躺著弄捕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪导帝。 梳的紋絲不亂的頭發(fā)上守谓,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音您单,去河邊找鬼斋荞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛虐秦,可吹牛的內(nèi)容都是我干的譬猫。 我是一名探鬼主播讯檐,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼羡疗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼染服!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起叨恨,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柳刮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后痒钝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秉颗,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年送矩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚕甥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡栋荸,死狀恐怖菇怀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晌块,我是刑警寧澤爱沟,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站匆背,受9級(jí)特大地震影響呼伸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钝尸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一括享、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧珍促,春花似錦铃辖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至沐悦,卻和暖如春成洗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背藏否。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工瓶殃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人副签。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓遥椿,卻偏偏與公主長(zhǎng)得像基矮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冠场,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容