go语言有gc。GC是指垃圾回收,是一种自动内存管理的机制;go语言支持GC,Go语言中对象内存空间的回收是通过GC机制来完成的。对于Go语言而言,Go语言的GC使用的是无分代(对象没有代际之分)、不整理(回收过程中不对对象进行移动与整理)、并发(与用户代码并发执行)的三色标记清扫算法。
本教程操作环境: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嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!