GoGc

linux內(nèi)存布局

要搞懂gc前我們需要知道gc到底在回收什么。而想到知道gc在回收什么不可避免的就必須要清楚進程的內(nèi)存布局了肤舞。


image.png
  1. kernel space 內(nèi)核空間可以操作任意空間纲刀,而用戶空間如果需要操縱內(nèi)核空間项炼,需要由操作系統(tǒng)來完成,調(diào)用操作稱為系統(tǒng)調(diào)用(system call)示绊。
  2. stack是棧區(qū)锭部,常稱為堆棧。它的分配由高地址往低地址擴展面褐。棸韬蹋空間用于分配函數(shù)的出入?yún)⒑途植孔兞?/li>
  3. memory mapping是映射區(qū),比如一些外部的動態(tài)鏈接庫等展哭。
  4. heap是堆湃窍,和數(shù)據(jù)結(jié)構(gòu)中的堆沒有關(guān)系,它的分配由低地址往高地址分配匪傍。它用于存儲應(yīng)用程序動態(tài)申請的對象您市。
  5. bss是Block Started by Symbol的簡稱,屬于靜態(tài)內(nèi)存分配役衡。一般用來存放程序中未初始化的全局變量墨坚。
  6. data用來存儲一些常量數(shù)據(jù),一般用來存儲程序中已經(jīng)初始化的全局變量映挂。
  7. text用于加載程序自身代碼段泽篮。

go內(nèi)存管理

image.png

像go這種自帶runtime的語言基本上拋棄了傳統(tǒng)的內(nèi)存分配方式,改為自動管理柑船。這樣可以自主地實現(xiàn)更好的內(nèi)存使用模式帽撑,比如內(nèi)存池、預(yù)分配等等鞍时。這樣亏拉,不會每次內(nèi)存分配都需要進行系統(tǒng)調(diào)用。go內(nèi)存沒有內(nèi)存碎片也是因為這種分配模式而避免的逆巍。

協(xié)程棧雖然在堆上但是也是不需要gc回收

gc負責回收堆內(nèi)存及塘,而不回收棧(協(xié)程棧)中的內(nèi)存。主要是原因是棧為函數(shù)執(zhí)行準備的锐极,存儲著函數(shù)的局部變量以及調(diào)用棧笙僚,這塊內(nèi)存用完會直接釋放所以不需要gc來管理。(go的協(xié)程棧也是在堆內(nèi)存分配的灵再,不是傳統(tǒng)的棧肋层,go的棧有個stack cache pool亿笤,管理棧對象,回收已銷毀的棧還給stack cache pool栋猖,棧仍舊是調(diào)用完畢即銷毀净薛,包括棧中的臨時對象)。

變量逃逸

逃逸分析基本原則

  1. 指向堆棧對象的指針不能存儲在堆中蒲拉。(堆上的指針不能指向棧)
  2. 指向堆棧對象的指針不能超過那個對象的壽命肃拜。
type User struct {
  Name string
    Age int
}
func main() {
    GetUser()
}

func GetUser() *User {
  user := User{}
    return &user
}
/*由于 *user 這個指針被傳到 main 函數(shù)中使用,而 User 這個對象在 GetUser 方法中 New 出來雌团,如果不逃逸到堆上爆班,則指針的壽命比對象長。因此需要逃逸到堆上辱姨,讓對象的壽命比其指針長柿菩。因此上述例子發(fā)生了逃逸
*/

type User struct {
  Name string
    Age int
    Car *Car
}
type Car struct {
}

func main() {
    user := GetUser()
    car := Car{}
    user.Car = &car
}

func GetUser() *User {
    return &User{}
}

/*
`GetUser` 返回的是一個逃逸的對象,即其已經(jīng)存在堆中雨涛。我們給其一個字段賦值 `*Car`, 如果把 Car 對象分配在棧中枢舶,發(fā)生了指向 棧中對象(Car)的指針存儲在堆中對象中(User) ,違背了原則 1替久,所以 Car 對象需要逃逸到堆凉泄。`[fmt.Println](https://link.zhihu.com/?target=https%3A//github.com/golang/go/issues/8618)` 也是這個原因存在逃逸
*/

GC主要流程

根對象

全局變量:程序在編譯期就能確定的那些存在于程序整個生命周期的變量。
執(zhí)行棧:每個 goroutine 都包含自己的執(zhí)行棧蚯根,這些執(zhí)行棧上包含棧上的變量及指向分配的堆內(nèi)存區(qū)塊的指針后众。
寄存器:寄存器的值可能表示一個指針,參與計算的這些指針可能指向某些賦值器分配的堆內(nèi)存區(qū)塊颅拦。

三色標記法

三色抽象只是一種描述追蹤式回收器的方法蒂誉,在實踐中并沒有實際含義,它的重要作用在于從邏輯上嚴密推導(dǎo)標記清理這種垃圾回收方法的正確性距帅。
當垃圾回收開始時右锨,只有白色對象。隨著標記過程開始進行時碌秸,灰色對象開始出現(xiàn)(著色)绍移,這時候波面便開始擴大。當一個對象的所有子節(jié)點均完成掃描時讥电,會被著色為黑色蹂窖。當整個堆遍歷完成時,只剩下黑色和白色對象恩敌,這時的黑色對象為可達對象瞬测,即存活;而白色對象為不可達對象,即死亡涣楷。這個過程可以視為以灰色對象為波面分唾,將黑色對象和白色對象分離抗碰,使波面不斷向前推進狮斗,直到所有可達的灰色對象都變?yōu)楹谏珜ο鬄橹沟倪^程。


image.png

GC流程圖

這應(yīng)該是比較老版本的gc流程弧蝇,但是大致正確碳褒。


image.png
  1. Off 代表gc當前未開啟,一輪完整的Gc總是從Off狀態(tài)開啟的看疗。
  2. Stack Scan 收集根對象(全局變量和goroutine棧上的變量)這個節(jié)點會開啟寫屏障 沙峻。
    a. 不需要回收棧上的對象為什么需要掃描棧上的變量?
    b. 開啟寫屏障需要進行stw两芳。(這里go 1.14 做了什么優(yōu)化摔寨?)
  3. Mark 標記對象,知道標記完所有根對象和根對象可達對象怖辆,此時寫屏障會記錄所有指針的更改是复。
  4. Mark Termination 重新掃描部分全局變量和發(fā)生更改的棧變量,完成標記竖螃。(stw主要耗費時間)
  5. Sweep 并發(fā)清除為標記的對象淑廊。

GC的優(yōu)化迭代

上圖我們發(fā)現(xiàn)第二次的Stw需要很久,go是怎么優(yōu)化的呢特咆?答案是混合寫屏障
首先我們要知道為什么需要stw季惩?
因為標記工作和用戶邏輯代碼是并行的,標記完成后的棧重新執(zhí)行用戶代碼后可能會破壞當前的標記現(xiàn)場腻格。比如一個黑色對象因為業(yè)務(wù)代碼引用了堆上的白色對象画拾,如此垃圾回收的正確性就被破壞了。白色對象后續(xù)會被回收菜职,相當于棧上的一個對象引用了一個需要被回收的對象碾阁。為此解決這種情況有3種方案:

  1. 棧上使用寫屏障,(屏障就是用戶對變量操作時插入的特定代碼)些楣,被掃描后的棧就開啟寫屏障脂凶,所有引入的對象全部被標為黑色。
  2. 在gc過程中掃描后的棧正常運行愁茁,不做處理蚕钦,等掃描階段結(jié)束后,stw鹅很,重新對活躍的棧進行掃描嘶居。這也是上文做的方式。
  3. 對堆采用混合寫屏障,對棧不做處理邮屁。棧上運行
image.png

最終go采用了第三種方案整袁,性能和準確性上面都獲得了保證。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末佑吝,一起剝皮案震驚了整個濱河市坐昙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芋忿,老刑警劉巖炸客,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異戈钢,居然都是意外死亡痹仙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門殉了,熙熙樓的掌柜王于貴愁眉苦臉地迎上來开仰,“玉大人,你說我怎么就攤上這事薪铜≈诠” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵痕囱,是天一觀的道長田轧。 經(jīng)常有香客問我,道長鞍恢,這世上最難降的妖魔是什么傻粘? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮帮掉,結(jié)果婚禮上弦悉,老公的妹妹穿的比我還像新娘。我一直安慰自己蟆炊,他們只是感情好稽莉,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涩搓,像睡著了一般污秆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昧甘,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天良拼,我揣著相機與錄音,去河邊找鬼充边。 笑死庸推,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贬媒,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聋亡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了际乘?” 一聲冷哼從身側(cè)響起坡倔,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚓庭,沒想到半個月后致讥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仅仆,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡器赞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了墓拜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片港柜。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖咳榜,靈堂內(nèi)的尸體忽然破棺而出夏醉,到底是詐尸還是另有隱情,我是刑警寧澤涌韩,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布畔柔,位于F島的核電站,受9級特大地震影響臣樱,放射性物質(zhì)發(fā)生泄漏靶擦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一雇毫、第九天 我趴在偏房一處隱蔽的房頂上張望玄捕。 院中可真熱鬧,春花似錦棚放、人聲如沸枚粘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馍迄。三九已至,卻和暖如春局骤,著一層夾襖步出監(jiān)牢的瞬間攀圈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工庄涡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留量承,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像撕捍,于是被迫代替她去往敵國和親拿穴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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