大家好,我是小?,一個漂泊江湖多年的 985 非科班程序員,曾混跡于國企、互聯(lián)網(wǎng)大廠和創(chuàng)業(yè)公司的后臺開發(fā)攻城獅。
垃圾回收(Garbage collection,簡稱 GC)是內存管理中一個非常重要的話題,不管是何種編程語言,GC 的目標都是相同的,即準確高效地識別和清理內存中的垃圾對象。
不同編程語言在實現(xiàn)思路上有相似之處,又各自有不同的側重點,接下來我們對比 Python、Java 和 Go 的 GC 機制來展開聊聊。
Python 通過ob_refcnt字段,追蹤對象被引用的次數(shù),當計數(shù)減至零時,對象生命終結,即刻被垃圾回收機制回收。
這種方式簡單明了,即時回收無用對象,避免了程序中長時間占用無用內存的問題,但其自身不能處理循環(huán)引用。
Python 輔以標記-清除算法,主要處理容器對象的循環(huán)引用問題。Python 中的垃圾回收器會周期性地執(zhí)行,掃描對象,標記所有從根對象集合開始可訪問到的對象,未被標記的對象即被認定為垃圾,進行清除。
這種方式確保了即使在復雜關聯(lián)關系中,內存也能得到有效管理與釋放。
為了減少引用計數(shù)和標記-清除乃至內存整體的管理開銷,Python 引入了分代回收機制,該機制將對象分為不同的代(通常是三代),假設對象存活時間越長,越不可能成為垃圾,因此新生代的對象頻繁檢查回收,老年代對象檢查回收頻率則低,這樣可以大幅減少垃圾回收帶來的性能損耗。
Java 垃圾回收器根據(jù)從 GC Root 開始的引用鏈,判定對象是否可達。
所謂 GC Root,包括類靜態(tài)屬性、活動線程、JNI 引用等。若對象在引用鏈上,則視為可達;反之,視為垃圾。這種分析方法摒棄了引用計數(shù)的局限,有效避免了循環(huán)引用問題。
Java 內存空間被劃分為年輕代、老年代和永久代(后改進為元空間),這樣的分代機制讓 Java 的垃圾回收更高效。
年輕代適用更快的垃圾回收算法,因為年輕代對象生命周期短,死亡速度快。對于老年代,由于其包含生命周期長的對象,因此使用不同的回收策略,減少回收頻率,節(jié)約系統(tǒng)資源。
Java 提供了多種垃圾回收器,比如 Serial、Parallel、CMS、G1 及 ZGC 等,應對不同的使用場景。
比如,Serial 適合客戶端模式,而 G1 垃圾回收器更適合需要大內存、多核服務器環(huán)境使用,實現(xiàn)了高并發(fā)和低停頓時間,它們各取所長,為開發(fā)者提供了豐富的內存管理選項。
Go 語言自 v1.5 以來,采用了三色標記法,在程序運行期間進行垃圾回收,程序執(zhí)行并未完全中斷,這一并發(fā)垃圾回收機制提高了回收效率。
在操作中,對象在初始被視為白色(可能是垃圾),然后可達對象在遍歷過程中變?yōu)榛疑ù幚恚┖妥罱K的黑色(存活對象),未標記到的對象即為垃圾,準備被回收。
在垃圾收集領域,三色不變性是并發(fā)標記算法中的一個重要概念。想要在并發(fā)或者增量的標記算法中保證正確性,我們需要達成以下兩種三色不變性(Tri-color invariant)中的一種:
它確保了在整個標記過程中,不會錯誤地回收還在使用的對象。
混合寫屏障正是基于三色不變式的一種優(yōu)化實踐,它在 Go 的垃圾收集器中負責在并發(fā)標記階段維護三色不變式的正確性。在 Go v1.8 中引入后,混合寫屏障結合了“插入”和“刪除”屏障的策略,巧妙地減少了因為程序的運行而帶來的標記干擾。
插入屏障是指在對象引用時進行干預,而刪除屏障則是在對象引用被刪除時進行操作。通過這一策略,Go 確保了在對象圖的動態(tài)變化下,也不會因為遺漏對新活對象的標記或錯誤地標記死對象而破壞垃圾收集的準確性,這是并發(fā)收集算法中的一個巨大突破。
垃圾回收機制在內存管理中發(fā)揮著核心作用,有效地回收內存中的廢棄對象。
本文比較了 Python、Java 和Go 三種編程語言的垃圾回收策略。
本文鏈接:http://www.tebozhan.com/showinfo-26-85227-0.html不同編程語言的 GC 機制對比
聲明:本網(wǎng)頁內容旨在傳播知識,若有侵權等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 深入探索C++聯(lián)合體Union的神奇用法
下一篇: 呀,Python中居然還有字典推導式