golang的垃圾回收(GC)機制
然後再到這裡
golang的垃圾回收採用的是標記-清理(Mark-and-Sweep)演算法
就是先標記出需要回收的記憶體物件快,然後在清理掉;
在這裡不介紹標記和清理的具體策略(可以參考https://lengzzz.com/note/gc-in-golang),只介紹 GC過程是怎麼排程的以及stw相關
這個演算法,會導致 stw (stop the world)的問題,中斷使用者邏輯
觸發GC機制
1. 在申請記憶體的時候,檢查當前當前已分配的記憶體是否大於上次GC後的記憶體的2倍,若是則觸發(主GC執行緒為當前M)
2. 監控執行緒發現上次GC的時間已經超過兩分鍾了,觸發;將一個
每當觸發的時候,在主GC執行緒中就會走如下的GC流程:
1. stop the world,等待所有的M休眠;此時所有的業務邏輯代碼都停止
2. 標記:分配gc標記任務,喚醒 gcproc個 M(就是第一步休眠的那些),分別做這個,直到所有的M都做完,才結束;並且所有M再次進入休眠
3. 清理:有一個單獨的goroutine去清理已經標記的記憶體對象快
4. start the world,設置gcwaiting=0,喚醒所有的M(不會超過P個數)
對於上面的三個步驟,分別解釋:
stop the world
1. 設定gcwaiting=1,這個在每一個G任務之前會檢查一次這個狀態,如是,則會將當前M休眠;
2. 如果這個M裡面正在執行一個長時間的G任務,咋辦呢,難道會等待這個G任務自己切換嗎?這樣的話可要等10ms啊,不能等!堅決不能等!所以會主動發出搶佔標記(類似於上一篇),讓當前G任務中斷,再執行下一個G任務的時候,就會走到第1步
3. 一直等待所有的M進入休眠,此時所有的業務邏輯程式碼都停止
標記:
1. 根據gcproc的個數,分配成gcproc任務段;喚醒gcproc-1個M來執行(當前M也算一個)
2. 對於一個M,喚醒前設定它的helpgc標記,喚醒之後這個
3. 等每一個M都做完,會再次進入休眠
清理:
1. 通過設置引數,可以以一個單獨goroutine 執行,這個功能是在1.3版本之後增加的,這樣的話就直接到下一步了,清理過程不是stw的
2. 也可以序列的在主GC執行緒執行;這樣的話則清理過程也是stw的,
start the world:
1. 設定gcwaiting=0
2. 喚醒P個M來繼續做G任務(此時沒有helpgc標記),業務邏輯程式碼開始
綜上:
是基於1.4版本的,GC過程在標記過程是(STW)的
在1.5版本里面對GC做了很大的優化;採用三色標記,將標記過程細化成三段,只有前後的兩段是stw的;極大地縮短了gc的stw時間