首頁 >後端開發 >Golang >go語言有垃圾回收嗎

go語言有垃圾回收嗎

青灯夜游
青灯夜游原創
2022-12-09 19:42:387052瀏覽

go語言有垃圾回收。 Go語言自帶垃圾回收機制(GC);GC透過獨立的進程執行,它會搜尋不再使用的變量,並將其釋放。在計算中。記憶體空間包含兩個重要的區域:堆疊區(Stack) 和堆疊區(Heap);棧區一般儲存了函數呼叫的參數、返回值以及局部變量,不會產生記憶體碎片,由編譯器管理,無需開發者管理;而堆區會產生記憶體碎片,在Go語言中堆區的物件由記憶體分配器分配並由垃圾收集器回收。

go語言有垃圾回收嗎

本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。

Go語言自備垃圾回收機制(GC)。 GC 透過獨立的進程執行,它會搜尋不再使用的變量,並將其釋放。需要注意的是,GC 在運作時會佔用機器資源。

Go 語言中的垃圾回收機制GC 詳解

在電腦科學中,垃圾回收(Garbage Collection 簡稱GC) 是一種自動管理記憶體的機制,垃圾回收器會去嘗試回收程式不再使用的物件及佔用的記憶體

程式設計師受益於GC,無需操心、也不再需要對記憶體進行手動的申請和釋放操作,GC 在程式運行時自動釋放殘留的記憶體
GC 對程式設計師幾乎不可見,僅在程式需要進行特殊最佳化時,透過提供可調控的API,對GC 的運行時機、運行開銷進行把控的時候才得以現身

在運算中,記憶體空間包含兩個重要的區域:堆疊區(Stack) 和堆疊區(Heap);堆疊區一般儲存了函數呼叫的參數、傳回值以及局部變量,不會產生記憶體碎片,由編譯器管理,無需開發者管理;而堆區會產生記憶體碎片,在Go 語言中堆區的物件由記憶體分配器分配並由垃圾收集器回收。 【相關推薦:Go影片教學程式教學

通常,垃圾回收器的執行過程分為兩個半獨立的元件:

  • 使用者程式(Mutator):使用者程式碼,對於GC 而言,使用者態程式碼僅僅只是在修改物件之間的參考關係
  • 收集器(Colletor):負責執行垃圾回收的代碼

一、記憶體管理與分配

當記憶體不再使用時,Go 記憶體管理由其標準庫自動執行,即從記憶體分配到Go 集合。記憶體管理一般包含三個不同的元件,分別是使用者程式(Mutator)、分配器(Allocator) 和收集器(Collector),當使用者程式申請記憶體時,它會透過記憶體分配器申請新內存,而分配器會負責從堆中初始化對應的記憶體區域

go語言有垃圾回收嗎

#1.1 記憶體分配器的分配方法

在程式語言中,記憶體分配器一般有兩種分配方法:

  • 線性分配器(Sequential Allocator,Bump Allocator)

  • 空閒鍊錶分配器(Free-List Allocator)

線性分配器

線性分配(Bump Allocator) 是一種高效率的記憶體分配方法,但是有較大的限制。當使用者使用線性分配器時,只需要在內存中維護一個指向內存特定位置的指針,如果用戶程式向分配器申請內存,分配器只需要檢查剩餘的空閒內存、返回分配的內存區域並修改指針在記憶體中的位置;

雖然線性分配器有較快的執行速度以及較低的實作複雜度,但線性分配器無法在記憶體釋放後重複使用記憶體。如下圖,如果已經分配的記憶體被回收,線性分配器無法重新利用紅色的記憶體

go語言有垃圾回收嗎

#因此線性分配器需要與適合的垃圾回收演算法配合使用

  • 標記壓縮(Mark-Compact)

  • 複製回收(Copying GC)

  • 分代回收(Generational GC)

以上演算法可以透過拷貝的方式整理存活物件的碎片,將空閒記憶體定期合併,這樣就能利用線性分配器的效率提升記憶體分配器的效能了

空閒鍊錶分配器

空閒鍊錶分配器(Free-List Allocator) 可以重用已經被釋放的內存,它在內部會維護一個類似鍊錶的資料結構。當使用者程式申請記憶體時,空閒鍊錶分配器會依序遍歷空閒的記憶體區塊,找到足夠大的內存,然後申請新的資源並修改鍊錶

go語言有垃圾回收嗎

空閒鍊錶分配器常見有四個策略:

  • #第一次適應(First-Fit) — 從鍊錶頭開始遍歷,選擇第一個大小大於申請記憶體的記憶體區塊
  • 循環首次適應(Next-Fit) — 從上次遍歷的結束位置開始遍歷,選擇第一個大小大於申請記憶體的記憶體區塊
  • 最優適應(Best-Fit) — 從鍊錶頭遍歷整個鍊錶,選擇最合適的記憶體區塊
  • 隔離適應(Segregated-Fit) — 將記憶體分割成多個鍊錶,每個鍊錶中的記憶體區塊大小相同,申請記憶體時先找到滿足條件的鍊錶,再從鍊錶中選擇合適的記憶體區塊

#其中第四中策略與Go 語言中使用的記憶體分配策略相似

go語言有垃圾回收嗎

該策略會將記憶體分割成由4、8、16、32 位元組的記憶體區塊組成的鍊錶,當我們向記憶體分配器申請8 位元組的記憶體時,它會在上圖中找到滿足條件的空閒記憶體區塊並返回。隔離適應的分配策略減少了需要遍歷的記憶體區塊數量,提高了記憶體分配的效率

#1.2 Go 中的記憶體分配

##一張圖展示記憶體分配組成:

go語言有垃圾回收嗎

在Go 語言中,堆上的所有物件都會透過呼叫

runtime.newobject 函數分配內存,該函數會呼叫runtime.mallocgc 分配指定大小的記憶體空間,這也是使用者程式向堆上申請記憶體空間的必經函數

func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
	mp := acquirem()
	mp.mallocing = 1

	c := gomcache()
	var x unsafe.Pointer
	noscan := typ == nil || typ.ptrdata == 0
	if size 從程式碼中可以看出<p>runtime .mallocgc<code> 根據物件的大小執行不同的分配邏輯,根據物件大小將它們分成微物件、小物件和大物件</code></p>
    微物件
  • (0, 16B) — 先使用微型分配器,再依序嘗試執行緒快取、中心快取和堆分配記憶體
  • 小物件
  • [16B, 32KB] — 依序嘗試使用執行緒快取、中心快取和堆分配記憶體
  • 大物件
  • (32KB, ∞) — 直接在堆上分配記憶體

go語言有垃圾回收嗎

小分配

對於小於32kb 的小分配,Go 會嘗試從

mcache 的本地快取中獲取內存,該緩存處理一個跨度列表(32kb 的內存塊) mspan

go語言有垃圾回收嗎

每個執行緒M 都分配給一個處理器P,一次最多處理一個

goroutine。在分配記憶體時,目前的goroutine 將使用其目前的本機快取P 來尋找span 清單中第一個可用的空閒物件

##大分配

Go 不使用本機快取管理大型分配。這些大於32kb 的分配被四捨五入到頁面大小,頁面直接分配到堆中

go語言有垃圾回收嗎

二、垃圾回收在Go 語言中,垃圾回收器實現的演算法是一個並發的三色標記和掃描收集器

Roth回收器與Go 程式同時運行,因此需要透過一種

寫入屏障

演算法來偵測記憶體中的潛在變化。啟動寫入屏障的唯一條件是在短時間內停止程序,即「Stop the World」

go語言有垃圾回收嗎

寫屏障的目的是允許收集器在收集期間保持堆上的資料完整性

2.1 實作原理Go 語言的垃圾收集可以分成清除終止、標記、標記終止和清除四個不同的階段,其中兩個階段會產生Stop The World (STW)

go語言有垃圾回收嗎

#清除終止階段

暫停程序,所有的處理器在這時會進入安全點(Safe point)
  • 如果當前垃圾收集循環是強制觸發的,我們還需要處理還未被清理的記憶體管理單元
標記階段(STW)

#

  • 將狀態切換至_GCmark、開啟寫入屏障、使用者程式協助(Mutator Assists)並將根物件入隊

  • 恢復執行程序,標記進程和用於協助的用戶程式會開始並發標記記憶體中的對象,寫屏障會將被覆蓋的指針和新指針都標記成灰色,而所有新創建的對像都會被直接標記成黑色

  • 開始掃描根對象,包含所有Goroutine 的堆疊、全域物件以及不在堆疊中的執行時間資料結構,掃描Goroutine 堆疊期間會暫停目前處理器

  • #依序處理灰色佇列中的對象,將物件標記成黑色並將它們指向的物件標記成灰色

  • 使用分散式的終止演算法檢查剩餘的工作,發現標記階段完成後進入標記終止階段

標記終止階段(STW)

  • 暫停程式、將狀態切換至_GCmarktermination 並關閉輔助標記的使用者程式
  • 清理處理器上的執行緒快取

## 清理階段

    ##將狀態切換至
  • _GCoff

    開始清理階段,初始化清理狀態並關閉寫入屏障

  • 恢復使用者程序,所有新建立的物件都會標記成白色
  • 後台並發清理所有的記憶體管理單元,當Goroutine 申請新的記憶體管理單元時就會觸發清理

2.2 三色標記法三色標記演算法將程式中的物件分成白色、黑色和灰色三類:

白色物件— 潛在的垃圾,其記憶體可能會被垃圾收集器回收
  • 黑色物件— 活躍的對象,包括不存在任何引用外部指標的物件以及從根物件可達的物件
  • 灰色對象— 活躍的對象,因為存在指向白色對象的外部指針,垃圾收集器會掃描這些對象的子對象
  • 三色標記垃圾收集器的工作原理很簡單,可以將其歸納為以下幾個步驟:

    從灰色物件的集合中選擇一個灰色物件並將其標記成黑色
  • 將黑色物件指向的所有物件都標記成灰色,保證該物件和被該物件所引用的物件都不會被回收
  • 重複上述兩個步驟直到物件圖中不存在灰色對象

1go語言有垃圾回收嗎更多程式相關知識,請造訪:

程式設計影片

! !

以上是go語言有垃圾回收嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn