go語言有gc。GC是指垃圾回收,是一種自動記憶體管理的機制;go語言支援GC,Go中物件記憶體空間的回收是通過GC機制來完成的。對於Go而言,Go的GC使用的是無分代(物件沒有代際之分)、不整理(回收過程中不對物件進行移動與整理)、並行(與使用者程式碼並行執行)的三色標記清掃演演算法。
php入門到就業線上直播課:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
GC機制是在Java語言被廣泛使用之後所火起來的,像後來的指令碼語言Python都支援GC,GO也支援GC。
Go語言和C/C++語言的一個顯著的特點是Go中物件記憶體空間的回收是通過GC機制來完成的,不需要像C++一樣通過程式設計師的手動申請和釋放,所以Go中相對不容易出現記憶體漏失。今天我們就來聊聊Go中的GC機制。
什麼是GC,又有什麼用?
GC,全稱 Garbage Collection,即垃圾回收,是一種自動記憶體管理的機制。
當程式向作業系統申請的記憶體不再需要時,垃圾回收主動將其回收並供其他程式碼進行記憶體申請時候複用,或者將其歸還給作業系統,這種針對記憶體級別資源的自動回收過程,即為垃圾回收。而負責垃圾回收的程式元件,即為垃圾回收器。
垃圾回收其實一個完美的 「Simplicity is Complicated」 的例子。一方面,程式設計師受益於 GC,無需操心、也不再需要對記憶體進行手動的申請和釋放操作,GC 在程式執行時自動釋放殘留的記憶體。另一方面,GC 對程式設計師幾乎不可見,僅在程式需要進行特殊優化時,通過提供可調控的 API,對 GC 的執行時機、執行開銷進行把控的時候才得以現身。
通常,垃圾回收器的執行過程被劃分為兩個半獨立的元件:
賦值器(Mutator):這一名稱本質上是在指代使用者態的程式碼。因為對垃圾回收器而言,使用者態的程式碼僅僅只是在修改物件之間的參照關係,也就是在物件圖(物件之間參照關係的一個有向圖)上進行操作。
回收器(Collector):負責執行垃圾回收的程式碼。
GC中的根物件
根物件在垃圾回收的術語中又叫做根集合,它是垃圾回收器在標記過程時最先檢查的物件,包括:
全域性變數:程式在編譯期就能確定的那些存在於程式整個生命週期的變數。
執行棧:每個 goroutine 都包含自己的執行棧,這些執行棧上包含棧上的變數及指向分配的堆記憶體區塊的指標。
暫存器:暫存器的值可能表示一個指標,參與計算的這些指標可能指向某些賦值器分配的堆記憶體區塊。
GC的實現方式
所有的 GC 演演算法其存在形式可以歸結為追蹤(Tracing)和參照計數(Reference Counting)這兩種形式的混合運用。
追蹤式 GC
從根物件出發,根據物件之間的參照資訊,一步步推進直到掃描完畢整個堆並確定需要保留的物件,從而回收所有可回收的物件。Go、 Java、V8 對 JavaScript 的實現等均為追蹤式 GC。
參照計數式 GC
每個物件自身包含一個被參照的計數器,當計數器歸零時自動得到回收。因為此方法缺陷較多,在追求高效能時通常不被應用。Python、Objective-C 等均為參照計數式 GC。
目前比較常見的 GC 實現方式包括:
追蹤式,分為多種不同型別,例如:
標記清掃:從根物件出發,將確定存活的物件進行標記,並清掃可以回收的物件。
標記整理:為了解決記憶體碎片問題而提出,在標記過程中,將物件儘可能整理到一塊連續的記憶體上。
增量式:將標記與清掃的過程分批執行,每次執行很小的部分,從而增量的推進垃圾回收,達到近似實時、幾乎無停頓的目的。
增量整理:在增量式的基礎上,增加對物件的整理過程。
分代式:將物件根據存活時間的長短進行分類,存活時間小於某個值的為年輕代,存活時間大於某個值的為老年代,永遠不會參與回收的物件為永久代。並根據分代假設(如果一個物件存活時間不長則傾向於被回收,如果一個物件已經存活很長時間則傾向於存活更長時間)對物件進行回收。
參照計數:根據物件自身的參照計數來回收,當參照計數歸零時立即回收。
Go中GC的實現方式
對於 Go 而言,Go 的 GC 使用的是無分代(物件沒有代際之分)、不整理(回收過程中不對物件進行移動與整理)、並行(與使用者程式碼並行執行)的三色標記清掃演演算法。【相關推薦:Go視訊教學】
原因如下:
物件整理的優勢是解決記憶體碎片問題以及「允許」使用順序記憶體分配器。但 Go 執行時的分配演演算法基於 tcmalloc,基本上沒有碎片問題。並且順序記憶體分配器在多執行緒的場景下並不適用。Go 使用的是基於 tcmalloc 的現代記憶體分配演演算法,對物件進行整理不會帶來實質性的效能提升。
分代 GC 依賴分代假設,即 GC 將主要的回收目標放在新建立的物件上(存活時間短,更傾向於被回收),而非頻繁檢查所有物件。但 Go 的編譯器會通過逃逸分析將大部分新生物件儲存在棧上(棧直接被回收),只有那些需要長期存在的物件才會被分配到需要進行垃圾回收的堆中。也就是說,分代 GC 回收的那些存活時間短的物件在 Go 中是直接被分配到棧上,當 goroutine 死亡後棧也會被直接回收,不需要 GC 的參與,進而分代假設並沒有帶來直接優勢。並且 Go 的垃圾回收器與使用者程式碼並行執行,使得 STW 的時間與物件的代際、物件的 size 沒有關係。Go 團隊更關注於如何更好地讓 GC 與使用者程式碼並行執行(使用適當的 CPU 來執行垃圾回收),而非減少停頓時間這一單一目標上。
更多程式設計相關知識,請存取:!!
以上就是go語言有gc嗎的詳細內容,更多請關注TW511.COM其它相關文章!