go語言有垃圾回收。 Go語言自帶垃圾回收機制(GC);GC透過獨立的進程執行,它會搜尋不再使用的變量,並將其釋放。在計算中。記憶體空間包含兩個重要的區域:堆疊區(Stack) 和堆疊區(Heap);棧區一般儲存了函數呼叫的參數、返回值以及局部變量,不會產生記憶體碎片,由編譯器管理,無需開發者管理;而堆區會產生記憶體碎片,在Go語言中堆區的物件由記憶體分配器分配並由垃圾收集器回收。
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
Go語言自備垃圾回收機制(GC)。 GC 透過獨立的進程執行,它會搜尋不再使用的變量,並將其釋放。需要注意的是,GC 在運作時會佔用機器資源。
在電腦科學中,垃圾回收(Garbage Collection 簡稱GC) 是一種自動管理記憶體的機制,垃圾回收器會去嘗試回收程式不再使用的物件及佔用的記憶體
程式設計師受益於GC,無需操心、也不再需要對記憶體進行手動的申請和釋放操作,GC 在程式運行時自動釋放殘留的記憶體
GC 對程式設計師幾乎不可見,僅在程式需要進行特殊最佳化時,透過提供可調控的API,對GC 的運行時機、運行開銷進行把控的時候才得以現身
在運算中,記憶體空間包含兩個重要的區域:堆疊區(Stack) 和堆疊區(Heap);堆疊區一般儲存了函數呼叫的參數、傳回值以及局部變量,不會產生記憶體碎片,由編譯器管理,無需開發者管理;而堆區會產生記憶體碎片,在Go 語言中堆區的物件由記憶體分配器分配並由垃圾收集器回收。 【相關推薦:Go影片教學、程式教學】
通常,垃圾回收器的執行過程分為兩個半獨立的元件:
當記憶體不再使用時,Go 記憶體管理由其標準庫自動執行,即從記憶體分配到Go 集合。記憶體管理一般包含三個不同的元件,分別是使用者程式(Mutator)、分配器(Allocator) 和收集器(Collector),當使用者程式申請記憶體時,它會透過記憶體分配器申請新內存,而分配器會負責從堆中初始化對應的記憶體區域
在程式語言中,記憶體分配器一般有兩種分配方法:
線性分配器(Sequential Allocator,Bump Allocator)
空閒鍊錶分配器(Free-List Allocator)
線性分配器
線性分配(Bump Allocator) 是一種高效率的記憶體分配方法,但是有較大的限制。當使用者使用線性分配器時,只需要在內存中維護一個指向內存特定位置的指針,如果用戶程式向分配器申請內存,分配器只需要檢查剩餘的空閒內存、返回分配的內存區域並修改指針在記憶體中的位置;
雖然線性分配器有較快的執行速度以及較低的實作複雜度,但線性分配器無法在記憶體釋放後重複使用記憶體。如下圖,如果已經分配的記憶體被回收,線性分配器無法重新利用紅色的記憶體
#因此線性分配器需要與適合的垃圾回收演算法配合使用
標記壓縮(Mark-Compact)
複製回收(Copying GC)
分代回收(Generational GC)
以上演算法可以透過拷貝的方式整理存活物件的碎片,將空閒記憶體定期合併,這樣就能利用線性分配器的效率提升記憶體分配器的效能了
空閒鍊錶分配器
空閒鍊錶分配器(Free-List Allocator) 可以重用已經被釋放的內存,它在內部會維護一個類似鍊錶的資料結構。當使用者程式申請記憶體時,空閒鍊錶分配器會依序遍歷空閒的記憶體區塊,找到足夠大的內存,然後申請新的資源並修改鍊錶
空閒鍊錶分配器常見有四個策略:
#其中第四中策略與Go 語言中使用的記憶體分配策略相似
該策略會將記憶體分割成由4、8、16、32 位元組的記憶體區塊組成的鍊錶,當我們向記憶體分配器申請8 位元組的記憶體時,它會在上圖中找到滿足條件的空閒記憶體區塊並返回。隔離適應的分配策略減少了需要遍歷的記憶體區塊數量,提高了記憶體分配的效率
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>
— 先使用微型分配器,再依序嘗試執行緒快取、中心快取和堆分配記憶體
— 依序嘗試使用執行緒快取、中心快取和堆分配記憶體
— 直接在堆上分配記憶體
小分配
對於小於32kb 的小分配,Go 會嘗試從mcache 的本地快取中獲取內存,該緩存處理一個跨度列表(32kb 的內存塊)
mspan
goroutine。在分配記憶體時,目前的
goroutine 將使用其目前的本機快取P 來尋找
span 清單中第一個可用的空閒物件
Go 不使用本機快取管理大型分配。這些大於32kb 的分配被四捨五入到頁面大小,頁面直接分配到堆中
二、垃圾回收在Go 語言中,垃圾回收器實現的演算法是一個並發的三色標記和掃描收集器
Roth回收器與Go 程式同時運行,因此需要透過一種
寫入屏障演算法來偵測記憶體中的潛在變化。啟動寫入屏障的唯一條件是在短時間內停止程序,即「Stop the World」
寫屏障的目的是允許收集器在收集期間保持堆上的資料完整性暫停程序,所有的處理器在這時會進入安全點(Safe point)
# 將狀態切換至 恢復執行程序,標記進程和用於協助的用戶程式會開始並發標記記憶體中的對象,寫屏障會將被覆蓋的指針和新指針都標記成灰色,而所有新創建的對像都會被直接標記成黑色 開始掃描根對象,包含所有Goroutine 的堆疊、全域物件以及不在堆疊中的執行時間資料結構,掃描Goroutine 堆疊期間會暫停目前處理器 #依序處理灰色佇列中的對象,將物件標記成黑色並將它們指向的物件標記成灰色 使用分散式的終止演算法檢查剩餘的工作,發現標記階段完成後進入標記終止階段 標記終止階段(STW) ## 清理階段 開始清理階段,初始化清理狀態並關閉寫入屏障 更多程式相關知識,請造訪:
_GCmark
、開啟寫入屏障、使用者程式協助(Mutator Assists)並將根物件入隊
_GCmarktermination
並關閉輔助標記的使用者程式##將狀態切換至
2.2 三色標記法三色標記演算法將程式中的物件分成白色、黑色和灰色三類:
白色物件— 潛在的垃圾,其記憶體可能會被垃圾收集器回收
從灰色物件的集合中選擇一個灰色物件並將其標記成黑色
以上是go語言有垃圾回收嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!