https://waterflow.link/articles/
為壺關(guān)等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及壺關(guān)網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站建設(shè)、網(wǎng)站制作、壺關(guān)網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
文中提到的垃圾回收算法是基于go1.16之后的,讓我們直接進(jìn)入正題吧。
Go 更喜歡在堆棧上分配內(nèi)存,因此大多數(shù)內(nèi)存分配最終都會(huì)在棧上。 這意味著 Go 每個(gè) goroutine 都有一個(gè)堆棧,并且在可能的情況下,Go 會(huì)將變量分配給這個(gè)堆棧。 Go 編譯器試圖通過(guò)執(zhí)行逃逸分析來(lái)查看對(duì)象是否被外部變量引用。 如果編譯器可以確定一個(gè)變量的生命周期,它將被分配到一個(gè)堆棧中。 但是,如果變量的生命周期不明確,它將在堆上分配。 通常,如果 Go 程序有一個(gè)指向?qū)ο蟮闹羔?,則該對(duì)象存儲(chǔ)在堆上。 看看這個(gè)示例代碼:
type myStruct struct {
value int
}
var testStruct = myStruct{value: 0}
func addTwoNumbers(a int, b int) int {
return a + b
}
func myFunction() {
testVar1 := 123
testVar2 := 456
testStruct.value = addTwoNumbers(testVar1, testVar2)
}
func someOtherFunction() {
myFunction()
}
我們假設(shè)這是一個(gè)正在運(yùn)行的程序的一部分,因?yàn)槿绻@是整個(gè)程序,Go 編譯器會(huì)通過(guò)將變量分配到堆棧中來(lái)優(yōu)化它。 程序運(yùn)行時(shí):
testStruct 現(xiàn)在在堆上并且沒(méi)有分析,Go 運(yùn)行時(shí)不知道是否仍然需要它。 為此,Go 依賴于垃圾回收器。 垃圾回收器有兩個(gè)關(guān)鍵部分,一個(gè) mutator 和一個(gè)回收器。 回收器執(zhí)行垃圾收集邏輯并找到應(yīng)該釋放其內(nèi)存的對(duì)象。 mutator 執(zhí)行應(yīng)用程序代碼并將新對(duì)象分配給堆。 它還會(huì)在程序運(yùn)行時(shí)更新堆上的現(xiàn)有對(duì)象,其中包括在不再需要某些對(duì)象時(shí)使其無(wú)法訪問(wèn)。
Go 的垃圾收集器是一個(gè)非分代并發(fā)、三色標(biāo)記和清除垃圾回收器。 讓我們分解一下這些術(shù)語(yǔ)。
什么是分代:
由于“復(fù)制”算法對(duì)于存活時(shí)間長(zhǎng),大容量的儲(chǔ)存對(duì)象需要耗費(fèi)更多的移動(dòng)時(shí)間,和存在儲(chǔ)存對(duì)象的存活時(shí)間的差異。需要程序?qū)⑺鶕碛械膬?nèi)存空間分成若干分區(qū),并標(biāo)記為年輕代空間和年老代空間。程序運(yùn)行所需的存儲(chǔ)對(duì)象會(huì)先存放在年輕代分區(qū),年輕代分區(qū)會(huì)較為頻密進(jìn)行較為激進(jìn)垃圾回收行為,每次回收完成幸存的存儲(chǔ)對(duì)象內(nèi)的壽命計(jì)數(shù)器加一。當(dāng)年輕代分區(qū)存儲(chǔ)對(duì)象的壽命計(jì)數(shù)器達(dá)到一定閾值或存儲(chǔ)對(duì)象的占用空間超過(guò)一定閾值時(shí),則被移動(dòng)到年老代空間,年老代空間會(huì)較少運(yùn)行垃圾回收行為。一般情況下,還有永久代的空間,用于涉及程序整個(gè)運(yùn)行生命周期的對(duì)象存儲(chǔ),例如運(yùn)行代碼、數(shù)據(jù)常量等,該空間通常不進(jìn)行垃圾回收的操作。 通過(guò)分代,存活在局限域,小容量,壽命短的存儲(chǔ)對(duì)象會(huì)被快速回收;存活在全局域,大容量,壽命長(zhǎng)的存儲(chǔ)對(duì)象就較少被回收行為處理干擾?!S基百科
分代垃圾回收器專注于最近分配的對(duì)象。 但是,如前所述,編譯器優(yōu)化允許 Go 編譯器將具有已知生命周期的對(duì)象分配給堆棧。 這意味著更少的對(duì)象將在堆上,因此更少的對(duì)象將被垃圾回收。 這意味著在 Go 中不需要分代垃圾回收器。 因此,Go 使用了非分代垃圾回收器。 并發(fā)意味著回收器與 mutator 線程同時(shí)運(yùn)行。 因此,Go 使用非分代并發(fā)垃圾回收器。 標(biāo)記和清除是垃圾回收器的類型,三色是用于實(shí)現(xiàn)它的算法。
Go 通過(guò)幾個(gè)步驟實(shí)現(xiàn)了這一點(diǎn):
1、開(kāi)啟寫屏障
Go 通過(guò)一個(gè)名為 stop the world 的進(jìn)程讓所有 goroutine 到達(dá)垃圾回收安全點(diǎn)。 這會(huì)暫時(shí)停止程序運(yùn)行并打開(kāi)寫屏障以維護(hù)堆上的數(shù)據(jù)完整性。 這通過(guò)允許 goroutine 和回收器同時(shí)運(yùn)行來(lái)實(shí)現(xiàn)并發(fā)。
想要在并發(fā)或者增量的標(biāo)記算法中保證正確性,我們需要達(dá)成以下兩種三色不變性(Tri-color invariant)中的一種:
一旦所有的 goroutine 都打開(kāi)了寫屏障,Go 運(yùn)行時(shí)就會(huì)starts the world并讓workers執(zhí)行垃圾回收工作。
2、標(biāo)記階段
標(biāo)記是通過(guò)使用三色算法實(shí)現(xiàn)的。 當(dāng)標(biāo)記開(kāi)始時(shí),根對(duì)象是灰色的,其他對(duì)象都是白色的。 根是所有其他堆對(duì)象的源對(duì)象,并作為運(yùn)行程序的一部分被實(shí)例化。 垃圾回收器通過(guò)掃描堆棧、全局變量和堆指針開(kāi)始標(biāo)記以了解正在使用的內(nèi)容。 掃描堆棧時(shí),workers 停止 goroutine 并通過(guò)從根向下遍歷將所有找到的對(duì)象標(biāo)記為灰色。 掃描完成恢復(fù) goroutine。
三色標(biāo)記的工作原理:
下圖是準(zhǔn)備標(biāo)記:
下圖為當(dāng)有新對(duì)象生成時(shí),因?yàn)殚_(kāi)啟了寫屏障,會(huì)直接標(biāo)記為黑色
下圖為根對(duì)象可達(dá)的對(duì)象都標(biāo)記為黑色
3、清理階段
然后將灰色對(duì)象排入隊(duì)列以變?yōu)楹谏?,這表明它們?nèi)栽谑褂弥小?一旦所有灰色物體都變成黑色,回收器將再次stop the world并清理所有不再需要的白色節(jié)點(diǎn)。 然后應(yīng)用程序現(xiàn)在可以繼續(xù)運(yùn)行,直到它需要再次清理更多內(nèi)存。
下圖為STW然后清理白色對(duì)象
下圖為清理之后,恢復(fù)程序運(yùn)行
一旦程序分配了與正在使用的內(nèi)存成比例的額外內(nèi)存,此過(guò)程將再次啟動(dòng)。 GOGC
環(huán)境變量決定了這一點(diǎn),默認(rèn)設(shè)置為 100。 Go 源代碼將其描述為:
如果 GOGC=100 并且我們使用 4M,我們將在達(dá)到 8M 時(shí)再次進(jìn)行 GC(此標(biāo)記在 next_gc 變量中跟蹤)。 這使 GC 成本與分配成本成線性比例。 調(diào)整 GOGC 只會(huì)改變線性常數(shù)(以及使用的額外內(nèi)存量)。
網(wǎng)站題目:golang垃圾回收
轉(zhuǎn)載注明:http://chinadenli.net/article48/dsoidhp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、虛擬主機(jī)、做網(wǎng)站、靜態(tài)網(wǎng)站、小程序開(kāi)發(fā)、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)