溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang中的gc原理是什么

發布時間:2022-01-18 10:13:23 來源:億速云 閱讀:182 作者:iii 欄目:數據庫

今天小編給大家分享一下golang中的gc原理是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

gc出現

對于任何使用C語言的人,如果問他們C語言的最大煩惱是什么,其中許多人可能會回答說是指針和內存泄漏。以致于后出現的語言,都在幫助程序員來處理內存泄漏的問題,比較有名的語言java、python、go等等,都有一個比較重要的機制,那就是gc(Garbage Collection),也就是垃圾收集器。當然這也是得意于這些語言的特質,它們在運行的時候,都有一個諸如golang中runtime的機制,java中有jvm來管理。程序員不再需要考慮,我什么時候應該分配內存,什么時候應該回收內存。如果是從c語言開始學習編程的,應該對malloc和free非常熟悉,再寫代碼的時候回小心翼翼的使用這兩個函數。如果是學python的,根本就不會注意到這個問題,有不會關心這個方面的問題。比較值得說明的是,在c語言中使用char列表來存儲字符串,是一件非常麻煩的事情,在java等但是,就算如此,在日常的寫程序的過程中,程序員也應該注意gc方面的問題。一個比較差的設計,可能使得gc對于整個程序的負擔非常的大,可能會發現程序中gc的時間占比非常高。

gc的原理

gc常見的方式有:

引用計數(reference counting)每個對象維護一個引用計數器,當引用該對象的對象被銷毀或者更新的時候,被引用對象的引用計數器自動減 1,當被應用的對象被創建,或者賦值給其他對象時,引用 +1,引用為 0 的時候回收,思路簡單,但是頻繁更新引用計數器降低性能,存在循環以引用(php,Python所使用的)

標記清除(mark and sweep)就是 golang 所使用的,從根變量來時遍歷所有被引用對象,標記之后進行清除操作,對未標記對象進行回收,缺點:每次垃圾回收的時候都會暫停所有的正常運行的代碼,系統的響應能力會大大降低,各種 mark&swamp 變種(三色標記法),緩解性能問題。

分代搜集(generation)jvm 就使用的分代回收的思路。在面向對象編程語言中,絕大多數對象的生命周期都非常短。分代收集的基本思想是,將堆劃分為兩個或多個稱為代(generation)的空間。新創建的對象存放在稱為新生代(young generation)中(一般來說,新生代的大小會比 老年代小很多),隨著垃圾回收的重復執行,生命周期較長的對象會被提升(promotion)到老年代中(這里用到了一個分類的思路,這個是也是科學思考的一個基本思路)。

golang中的gc原理

go1.3以前gc最大的問題在于stw(stop the word),即在gc的時候需要暫停程序行為,然后進標記,最后將未標記的垃圾清除。如果頻繁的觸發gc的話,程序的運行就一卡一卡的。其基本的思路就是:

1.標記:在內存堆中(由于有的時候管理內存頁的時候要用到堆的數據結構,所以稱為堆內存)存儲著有一系列的對象,這些對象可能會與其他對象有關聯(references between these objects) a tracing garbage collector 會在某一個時間點上停止原本正在運行的程序,之后它會掃描 runtim e已經知道的的 object 集合(already known set of objects),通常它們是存在于 stack 中的全局變量以及各種對象。gc 會對這些對象進行標記,將這些對象的狀態標記為可達,從中找出所有的,從當前的這些對象可以達到其他地方的對象的 reference,并且將這些對象也標記為可達的對象,這個步驟被稱為 mark phase,即標記階段,這一步的主要目的是用于獲取這些對象的狀態信息。

2.回收:一旦將所有的這些對象都掃描完,gc 就會獲取到所有的無法 reach 的對象(狀態為 unreachable 的對象),并且將它們回收,這一步稱為 sweep phase,即是清掃階段。

3.清除:gc 僅僅搜集那些未被標記為可達(reachable)的對象。如果 gc 沒有識別出一個 reference,最后有可能會將一個仍然在使用的對象給回收掉,就引起了程序運行錯誤。

go在1.3的時候引入了并發清理,go team 自己的說法是減少了 50%-70% 的暫停時間。
go在1.5時候使用了三色標記法,這個是標記清除算法的一個升級變種。流程如下:

1.灰色:對象已被標記,但這個對象包含的子對象未標記

2.黑色:對象已被標記,且這個對象包含的子對象也已標記,gcmarkBits對應的位為1(該對象不會在本次GC中被清理)

3.白色:對象未被標記,gcmarkBits對應的位為0(該對象將會在本次GC中被清理)

例如,當前內存中有A~F一共6個對象,根對象a,b本身為棧上分配的局部變量,根對象a、b分別引用了對象A、B, 而B對象又引用了對象D,則GC開始前各對象的狀態如下圖所示:

1.初始狀態下所有對象都是白色的。

2.接著開始掃描根對象a、b; 由于根對象引用了對象A、B,那么A、B變為灰色對象,接下來就開始分析灰色對象,分析A時,A沒有引用其他對象很快就轉入黑色,B引用了D,則B轉入黑色的同時還需要將D轉為灰色,進行接下來的分析。

3.灰色對象只有D,由于D沒有引用其他對象,所以D轉入黑色。標記過程結束

4.最終,黑色的對象會被保留下來,白色對象會被回收掉。

go中的gc過程

GO的GC是并行GC, 也就是GC的大部分處理和普通的go代碼是同時運行的, 這讓GO的GC流程比較復雜。

1.Stack scan:Collect pointers from globals and goroutine stacks。收集根對象(全局變量,和G stack),開啟寫屏障。全局變量、開啟寫屏障需要STW,G stack只需要停止該G就好,時間比較少。

2.Mark: Mark objects and follow pointers。標記所有根對象, 和根對象可以到達的所有對象不被回收。

3.Mark Termination: Rescan globals/changed stack, finish mark。重新掃描全局變量,和上一輪改變的stack(寫屏障),完成標記工作。這個過程需要STW。

4.Sweep: 按標記結果清掃span

從1.8以后的golang將第一步的stop the world 也取消了,這又是一次優化;1.9開始, 寫屏障的實現使用了Hybrid Write Barrier, 大幅減少了第二次STW的時間.
因為go支持并行GC, GC的掃描和go代碼可以同時運行, 這樣帶來的問題是GC掃描的過程中go代碼有可能改變了對象的依賴樹。
例如開始掃描時發現根對象A和B, B擁有C的指針。

1.GC先掃描A,A放入黑色

2.B把C的指針交給A

3.GC再掃描B,B放入黑色

4.C在白色,會回收;但是A其實引用了C。

為了避免這個問題, go在GC的標記階段會啟用寫屏障(Write Barrier)。啟用了寫屏障(Write Barrier)后,在GC第三輪rescan階段,根據寫屏障標記將C放入灰色,防止C丟失。

以上就是“golang中的gc原理是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女