【Golang】GC探秘/寫屏障是什么?

之前寫了 一篇【Golang】內存管理 ,有了很多的閱讀量,那么我就接著分享一下Golang的GC相關的學習。

由于Golang的GC機制一直在持續迭代,本文敘述的主要是Go1.9版本及以后的GC機制,該版本中Golang引入了 混合寫屏障大幅度地優化了STW的時間。具體GC機制的版本迭代可以參考 :GC的過去、現在和未來

基本概念

GC的對象

不再被需要的內存塊,如果無法回收這部分內存將無法重復使用

內存泄漏

不再被需要的內存塊,未在預期時間以內被回收的稱為內存泄漏

常見的GC方法:

1.【PHP,Swift,Python等】引用計數法:

  • 每個對象維護一個自身被引用的次數,當一個引用者消息后該計數-1;
  • 它的優勢為GC時查找需要回收的對象很簡單:只需要找到引用計數為0的對象即可;
  • 它的劣勢為在寫入引用關系時需要額外維護引用計數,帶來一定開銷 ;
    2.【Golang】標記清除法:
  • 每次GC時通過從根對象出發遞歸地查詢所有對象的引用關系,將無引用的對象進行標記后再行清理。
  • 它的優勢在于寫入引用關系時無額外開銷
  • 它的劣勢在于GC時查詢引用關系有一定開銷 ,有時還需要STW從而影響性能
STW: Stop the world

為了避免在GC的過程中,對象之間的引用關系發生新的變更使得GC的結果發生錯誤(比如GC過程中新增了一個引用,但是由于未掃描到該引用導致將被引用的對象清除了),停止所有正在運行的協程。
STW對性能有一些影響,Golang目前已經可以做到1ms以下的STW。

三色標記法

Golang中的GC方式為標記后清除,所采用的邏輯為——三色標記法:一開始全部的對象都是白色的


三色標記法
  1. 從root對象開始(全局變量+全局棧+當前活躍的goroutines中的棧),將它們加入到灰色隊列中,進行遍歷:類似于二叉樹使用隊列進行BFS遍歷的過程
  2. 從灰色隊列中pop出一個對象
  3. 將其引用的對象都置為灰色,加入到灰色隊列中
  4. 將該對象置為黑色
  5. 直到灰色隊列為空時,剩余的無引用的白色對象即會被清除

內存回收

看不太明白的可以參考我的上一篇文章:【Golang】內存管理

  1. 被回收的內存塊會被回收到MCache(Processor私有內存)結構中 ,對應的MSpan(塊類型)的allocBits的bitmap中對應的位置會被從1改為 0
  2. MSpan中除了allocBits還有另一個bitmap:GCMarkBits用于存放需要清除的標記:黑色=1,白色=0,一次GC之后所有MSpan中的GCMarkBits和AllocBits應該完全相同,因為只有黑色的內存對象在GC之后才會保留下來

寫屏障

上文有提到為了避免GC的過程中新修改的引用關系到GC的結果發生錯誤,我們需要進行STW。但是STW會影響程序的性能,所以我們要通過寫屏障技術盡可能地縮短STW的時間。

造成引用對象丟失的條件
  1. 一個黑色的節點A新增了指向白色節點C的引用
  2. 并且白色節點C沒有除了A之外的其他灰色節點的引用,或者存在但是在GC過程中被刪除了

以上兩個條件需要同時滿足:滿足條件1時說明節點A已掃描完畢,A指向C的引用無法再被掃描到;滿足條件2時說明白色節點C無其他灰色節點的引用了,即掃描結束后會被忽略 。

寫屏障破壞兩個條件其一即可
  1. 破壞條件1 => Dijistra寫屏障
  • 滿足強三色不變性:黑色節點不允許引用白色節點
  • 當黑色節點新增了白色節點的引用時,將對應的白色節點改為灰色
  1. 破壞條件2 => Yuasa寫屏障
  • 滿足弱三色不變性:黑色節點允許引用白色節點,但是該白色節點有其他灰色節點間接的引用(確保不會被遺漏)
  • 當白色節點被刪除了一個引用時,悲觀地認為它一定會被一個黑色節點新增引用,所以將它置為灰色
寫屏障的分類

注意:由于棧上的操作需要保證性能,所以所有的寫屏障均只針對堆上的對象。

寫屏障的分類

GC的時機

  1. 每次內存分配時檢查當前內存分配量是否已達到閾值(環境變量GOGC):默認100%,即當內存擴大一倍時啟用GC
  2. 定時觸發:當最近2分鐘未觸發過GC時,會觸發一次GC
  3. 通過runtime.GC()手動觸發

GC的優化

分配的對象越多,GC性能就越差,所以需要減少對象分配的個數,比如對象復用,使用sync.Pool

注意:sync.Pool類似于緩存,其中的對象會被定期清理(GC時清理),不能放置像是數據庫連接這樣需要穩定存儲的數據

參考

1.三色標記法是什么?
2.Go語言垃圾收集器原理

最后編輯于:2025-02-05 20:55:05


喜歡的朋友記得點贊、收藏、關注哦!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70045.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70045.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70045.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DeepSeek教unity------MessagePack-03

數據契約兼容性 你可以使用 [DataContract] 注解代替 [MessagePackObject]。如果類型用 DataContract 進行注解,可以使用 [DataMember] 注解代替 [Key],并使用 [IgnoreDataMember] 代替 [IgnoreMember]。 然后,[DataMember(Order int)] 的…

【對比】Pandas 和 Polars 的區別

Pandas vs Polars 對比表 特性PandasPolars開發語言Python(Cython 實現核心部分)Rust(高性能系統編程語言)性能較慢,尤其在大數據集上(內存占用高,計算效率低)極快,利用…

百度千帆平臺對接DeepSeek官方文檔

目錄 第一步:注冊賬號,開通千帆服務 第二步:創建應用,獲取調用秘鑰 第三步:調用模型,開啟AI對話 方式一:通過API直接調用 方式二:使用SDK快速調用 方式三:在千帆大模…

49. c++計時器

為了測試某段特定代碼的執行時間&#xff0c;體現代碼的性能&#xff0c;可以使用計時器對代碼段計時。下面使用std::chrono中的api編寫簡單案例&#xff1a; // // main.cpp // HelloWorld // // Created by on 2024/11/28. //#include <iostream> #include <vec…

Natural Language Processing NLP

NLP 清晰版本查看 Sentence segmentation (split)Tokenisation (split)Named entity recognition (combine) 概念主要內容典型方法Distributional Semantics&#xff08;分佈式語義&#xff09;&#xff08;分銷語義&#xff08;分佈式語義&#xff09;單詞的語義來自於它的…

Linux中線程創建,線程退出,線程接合

線程的簡單了解 之前我們了解過 task_struct 是用于描述進程的核心數據結構。它包含了一個進程的所有重要信息&#xff0c;并且在進程的生命周期內保持更新。我們想要獲取進程相關信息往往從這里得到。 在Linux中&#xff0c;線程的實現方式與進程類似&#xff0c;每個線程都…

HarmonyOS:使用List實現分組列表(包含粘性標題)

一、支持分組列表 在列表中支持數據的分組展示&#xff0c;可以使列表顯示結構清晰&#xff0c;查找方便&#xff0c;從而提高使用效率。分組列表在實際應用中十分常見&#xff0c;如下圖所示聯系人列表。 聯系人分組列表 在List組件中使用ListItemGroup對項目進行分組&#…

django上傳文件

1、settings.py配置 # 靜態文件配置 STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR /static, ]上傳文件 # 定義一個視圖函數&#xff0c;該函數接收一個 request 參數 from django.shortcuts import render # 必備引入 import json from django.views.decorators.http i…

【前端知識】瀏覽器兼容方案polyfill

瀏覽器兼容方案polyfill 什么是 Polyfill&#xff1f;Polyfill 的作用Polyfill 的工作原理1. **特性檢測**2. **加載 Polyfill**3. **模擬實現** Polyfill 的常見場景Polyfill 的使用方式Polyfill 的優缺點優點缺點 常見的 Polyfill 庫總結 什么是 Polyfill&#xff1f; Polyf…

C#學習之DateTime 類

目錄 一、DateTime 類的常用方法和屬性的匯總表格 二、常用方法程序示例 1. 獲取當前本地時間 2. 獲取當前 UTC 時間 3. 格式化日期和時間 4. 獲取特定部分的時間 5. 獲取時間戳 6. 獲取時區信息 三、總結 一、DateTime 類的常用方法和屬性的匯總表格 在 C# 中&#x…

dedecms 開放重定向漏洞(附腳本)(CVE-2024-57241)

免責申明: 本文所描述的漏洞及其復現步驟僅供網絡安全研究與教育目的使用。任何人不得將本文提供的信息用于非法目的或未經授權的系統測試。作者不對任何由于使用本文信息而導致的直接或間接損害承擔責任。如涉及侵權,請及時與我們聯系,我們將盡快處理并刪除相關內容。 0x0…

如何選擇合適的超參數來訓練Bert和TextCNN模型?

選擇合適的超參數來訓練Bert和TextCNN模型是一個復雜但關鍵的過程&#xff0c;它會顯著影響模型的性能。以下是一些常見的超參數以及選擇它們的方法&#xff1a; 1. 與數據處理相關的超參數 最大序列長度&#xff08;max_length&#xff09; 含義&#xff1a;指輸入到Bert模…

AWS 前端自動化部署流程指南

本文詳細介紹從前端代碼開發到 AWS 自動化部署的完整流程。 一、流程概覽 1.1 部署流程圖 #mermaid-svg-nYg7k6L5IKVBjDtr {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-nYg7k6L5IKVBjDtr .error-icon{fill:#552…

Office word打開加載比較慢處理方法

1.添加safe參數 ,找到word啟動項,右擊word,選擇屬性 , 添加/safe , 應用并確定 2.取消加載項,點擊文件,點擊選項 ,點擊加載項,點擊轉到,取消所有勾選,確定。

大數據SQL調優專題——Spark執行原理

引入 在深入MapReduce中有提到&#xff0c;MapReduce雖然通過“分而治之”的思想&#xff0c;解決了海量數據的計算處理問題&#xff0c;但性能還是不太理想&#xff0c;這體現在兩個方面&#xff1a; 每個任務都有比較大的overhead&#xff0c;都需要預先把程序復制到各個 w…

MYSQL下載安裝及使用

MYSQL官網下載地址&#xff1a;https://downloads.mysql.com/archives/community/ 也可以直接在服務器執行指令下載&#xff0c;但是下載速度比較慢。還是自己下載好拷貝過來比較快。 wget https://dev.mysql.com/get/Downloads/mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz 1…

CentOS 7.8 安裝MongoDB 7 副本集(Replica Set)

文章目錄 1 環境假設步驟1&#xff1a;在兩臺服務器上安裝MongoDB步驟2&#xff1a;配置副本集步驟3&#xff1a;初始化副本集步驟4&#xff1a;驗證副本集配置步驟5&#xff1a;設置安全性&#xff08;可選&#xff09;擴展配置示例&#xff1a;最佳實踐&#xff1a;仲裁節點步…

AJAX 與 ASP 的深入探討

AJAX 與 ASP 的深入探討 引言 隨著互聯網技術的飛速發展,Web應用程序的交互性和性能要求越來越高。AJAX(Asynchronous JavaScript and XML)和ASP(Active Server Pages)作為兩種重要的Web開發技術,在提高Web應用程序性能和用戶體驗方面發揮著重要作用。本文將深入探討AJ…

內網下,Ubuntu (24.10) 離線安裝docker最新版教程

一般在數據比較敏感的情況下&#xff0c;是無法使用網絡的&#xff0c;而對于Ubuntu系統來說&#xff0c;怎么離線安裝docker呢&#xff1f; 下面我給大家來講一下&#xff1a; 采用二進制安裝&#xff1a; 1.下載docker離線包 官網下載&#xff1a; Index of linux/static…

Copilot Next Edit Suggestions(預覽版)

作者&#xff1a;Brigit Murtaugh&#xff0c;Burke Holland 排版&#xff1a;Alan Wang 我們很高興向你介紹在本次 Visual Studio Code 發布中&#xff0c;關于 GitHub Copilot 的三個預覽功能&#xff1a; Next Edit Suggestions&#xff08;NES&#xff09;Copilot Edits 的…