成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 什么時候會觸發 GC?

開發 后端
Go 語言作為一門新語言,在早期經常遭到唾棄的就是在垃圾回收(下稱:GC)機制中 STW(Stop-The-World)的時間過長。

[[426528]]

本文轉載自微信公眾號「腦子進煎魚了」,作者陳煎魚 。轉載本文請聯系腦子進煎魚了公眾號。

大家好,我是煎魚。

Go 語言作為一門新語言,在早期經常遭到唾棄的就是在垃圾回收(下稱:GC)機制中 STW(Stop-The-World)的時間過長。

那么這個時候,我們又會好奇一點,作為 STW 的起始,Go 語言中什么時候才會觸發 GC 呢?

今天就由煎魚帶大家一起來學習研討一輪。

什么是 GC

在計算機科學中,垃圾回收(GC)是一種自動管理內存的機制,垃圾回收器會去嘗試回收程序不再使用的對象及其占用的內存。

最早 John McCarthy 在 1959 年左右發明了垃圾回收,以簡化 Lisp 中的手動內存管理的機制(來自 @wikipedia)。

為什么要 GC

手動管理內存挺麻煩,管錯或者管漏內存也很糟糕,將會直接導致程序不穩定(持續泄露)甚至直接崩潰。

GC 觸發場景

GC 觸發的場景主要分為兩大類,分別是:

  • 系統觸發:運行時自行根據內置的條件,檢查、發現到,則進行 GC 處理,維護整個應用程序的可用性。
  • 手動觸發:開發者在業務代碼中自行調用 runtime.GC 方法來觸發 GC 行為。

系統觸發

在系統觸發的場景中,Go 源碼的 src/runtime/mgc.go 文件,明確標識了 GC 系統觸發的三種場景,分別如下:

  1. const ( 
  2.  gcTriggerHeap gcTriggerKind = iota 
  3.  gcTriggerTime 
  4.  gcTriggerCycle 
  • gcTriggerHeap:當所分配的堆大小達到閾值(由控制器計算的觸發堆的大小)時,將會觸發。
  • gcTriggerTime:當距離上一個 GC 周期的時間超過一定時間時,將會觸發。-時間周期以 runtime.forcegcperiod 變量為準,默認 2 分鐘。
  • gcTriggerCycle:如果沒有開啟 GC,則啟動 GC。

在手動觸發的 runtime.GC 方法中涉及。

手動觸發

在手動觸發的場景下,Go 語言中僅有 runtime.GC 方法可以觸發,也就沒什么額外的分類的。

但我們要思考的是,一般我們在什么業務場景中,要涉及到手動干涉 GC,強制觸發他呢?

需要手動強制觸發的場景極其少見,可能會是在某些業務方法執行完后,因其占用了過多的內存,需要人為釋放。又或是 debug 程序所需。

基本流程

在了解到 Go 語言會觸發 GC 的場景后,我們進一步看看觸發 GC 的流程代碼是怎么樣的,我們可以借助手動觸發的 runtime.GC 方法來作為突破口。

核心代碼如下:

  1. func GC() { 
  2.  n := atomic.Load(&work.cycles) 
  3.  gcWaitOnMark(n) 
  4.  
  5.  gcStart(gcTrigger{kind: gcTriggerCycle, n: n + 1}) 
  6.    
  7.  gcWaitOnMark(n + 1) 
  8.  
  9.  for atomic.Load(&work.cycles) == n+1 && sweepone() != ^uintptr(0) { 
  10.   sweep.nbgsweep++ 
  11.   Gosched() 
  12.  } 
  13.    
  14.  for atomic.Load(&work.cycles) == n+1 && atomic.Load(&mheap_.sweepers) != 0 { 
  15.   Gosched() 
  16.  } 
  17.    
  18.  mp := acquirem() 
  19.  cycle := atomic.Load(&work.cycles) 
  20.  if cycle == n+1 || (gcphase == _GCmark && cycle == n+2) { 
  21.   mProf_PostSweep() 
  22.  } 
  23.  releasem(mp) 

在開始新的一輪 GC 周期前,需要調用 gcWaitOnMark 方法上一輪 GC 的標記結束(含掃描終止、標記、或標記終止等)。

開始新的一輪 GC 周期,調用 gcStart 方法觸發 GC 行為,開始掃描標記階段。

需要調用 gcWaitOnMark 方法等待,直到當前 GC 周期的掃描、標記、標記終止完成。

需要調用 sweepone 方法,掃描未掃除的堆跨度,并持續掃除,保證清理完成。在等待掃除完畢前的阻塞時間,會調用 Gosched 讓出。

在本輪 GC 已經基本完成后,會調用 mProf_PostSweep 方法。以此記錄最后一次標記終止時的堆配置文件快照。

結束,釋放 M。

在哪觸發

看完 GC 的基本流程后,我們有了一個基本的了解。但可能又有小伙伴有疑惑了?

本文的標題是 “GC 什么時候會觸發 GC”,雖然我們前面知道了觸發的時機。但是....Go 是哪里實現的觸發的機制,似乎在流程中完全沒有看到?

監控線程

實質上在 Go 運行時(runtime)初始化時,會啟動一個 goroutine,用于處理 GC 機制的相關事項。

代碼如下:

  1. func init() { 
  2.  go forcegchelper() 
  3.  
  4. func forcegchelper() { 
  5.  forcegc.g = getg() 
  6.  lockInit(&forcegc.lock, lockRankForcegc) 
  7.  for { 
  8.   lock(&forcegc.lock) 
  9.   if forcegc.idle != 0 { 
  10.    throw("forcegc: phase error"
  11.   } 
  12.   atomic.Store(&forcegc.idle, 1) 
  13.   goparkunlock(&forcegc.lock, waitReasonForceGCIdle, traceEvGoBlock, 1) 
  14.     // this goroutine is explicitly resumed by sysmon 
  15.   if debug.gctrace > 0 { 
  16.    println("GC forced"
  17.   } 
  18.  
  19.   gcStart(gcTrigger{kind: gcTriggerTime, now: nanotime()}) 
  20.  } 

在這段程序中,需要特別關注的是在 forcegchelper 方法中,會調用 goparkunlock 方法讓該 goroutine 陷入休眠等待狀態,以減少不必要的資源開銷。

在休眠后,會由 sysmon 這一個系統監控線程來進行監控、喚醒等行為:

  1. func sysmon() { 
  2.  ... 
  3.  for { 
  4.   ... 
  5.   // check if we need to force a GC 
  6.   if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && atomic.Load(&forcegc.idle) != 0 { 
  7.    lock(&forcegc.lock) 
  8.    forcegc.idle = 0 
  9.    var list gList 
  10.    list.push(forcegc.g) 
  11.    injectglist(&list) 
  12.    unlock(&forcegc.lock) 
  13.   } 
  14.   if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace)*1000000 <= now { 
  15.    lasttrace = now 
  16.    schedtrace(debug.scheddetail > 0) 
  17.   } 
  18.   unlock(&sched.sysmonlock) 
  19.  } 

這段代碼核心的行為就是不斷地在 for 循環中,對 gcTriggerTime 和 now 變量進行比較,判斷是否達到一定的時間(默認為 2 分鐘)。

若達到意味著滿足條件,會將 forcegc.g 放到全局隊列中接受新的一輪調度,再進行對上面 forcegchelper 的喚醒。

堆內存申請

在了解定時觸發的機制后,另外一個場景就是分配的堆空間的時候,那么我們要看的地方就非常明確了。

那就是運行時申請堆內存的 mallocgc 方法。核心代碼如下:

  1. func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { 
  2.  shouldhelpgc := false 
  3.  ... 
  4.  if size <= maxSmallSize { 
  5.   if noscan && size < maxTinySize { 
  6.    ... 
  7.    // Allocate a new maxTinySize block. 
  8.    span = c.alloc[tinySpanClass] 
  9.    v := nextFreeFast(span) 
  10.    if v == 0 { 
  11.     v, span, shouldhelpgc = c.nextFree(tinySpanClass) 
  12.    } 
  13.    ... 
  14.    spc := makeSpanClass(sizeclass, noscan) 
  15.    span = c.alloc[spc] 
  16.    v := nextFreeFast(span) 
  17.    if v == 0 { 
  18.     v, span, shouldhelpgc = c.nextFree(spc) 
  19.    } 
  20.    ... 
  21.   } 
  22.  } else { 
  23.   shouldhelpgc = true 
  24.   span = c.allocLarge(size, needzero, noscan) 
  25.   ... 
  26.  } 
  27.  
  28.  if shouldhelpgc { 
  29.   if t := (gcTrigger{kind: gcTriggerHeap}); t.test() { 
  30.    gcStart(t) 
  31.   } 
  32.  } 
  33.  
  34.  return x 

小對象:如果申請小對象時,發現當前內存空間不存在空閑跨度時,將會需要調用 nextFree 方法獲取新的可用的對象,可能會觸發 GC 行為。

大對象:如果申請大于 32k 以上的大對象時,可能會觸發 GC 行為。

總結

在這篇文章中,我們介紹了 Go 語言觸發 GC 的兩大類場景,并分別基于大類中的細分場景進行了一一說明。

一般來講,我們對其了解大概就可以了。若小伙伴們對其內部具體實現感興趣,也可以以文章中的代碼具體再打開看。

但需要注意,很有可能 Go 版本一升級,可能又變了,學思想要緊!

 

責任編輯:武曉燕 來源: 腦子進煎魚了
相關推薦

2024-10-29 08:52:01

Go協作式調度

2021-04-19 09:20:01

Go 搶占 P語言

2023-06-06 16:54:00

2015-03-02 14:44:48

AngularJS jQuery超越

2025-02-28 09:04:08

2023-02-01 15:49:51

人工智能AI

2020-05-12 11:25:50

MySQLES數據庫

2017-05-15 09:55:07

2015-07-08 15:55:01

NSStringcopystrong

2013-11-28 16:03:24

2012-09-24 10:20:39

JavaScriptJS

2022-05-19 10:27:34

機器學習人工智能

2024-08-05 01:22:16

2017-06-28 15:06:51

PythonLambda函數

2021-08-13 11:31:23

HTTP

2015-10-20 15:59:57

注釋代碼程序

2015-10-26 09:38:52

避免注釋代碼

2025-05-15 08:50:00

MQRPC架構

2023-02-14 07:31:30

ARMx86蘋果

2020-01-05 23:28:51

MQ消息進程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 黄色毛片黄色毛片 | 久久久久国产一级毛片高清网站 | 欧美在线观看免费观看视频 | 免费在线h视频 | 国产精品不卡视频 | 精品亚洲一区二区三区 | 91中文字幕在线 | 黄色片视频免费 | 成人免费视频网站在线看 | 亚洲精品久久久久久首妖 | 99在线免费视频 | 91精品国产综合久久久久 | 成人久久久 | 中文字幕国产视频 | 精品一区二区三区91 | 九九免费视频 | 九九av| 国产激情精品一区二区三区 | 亚洲免费在线 | 91视频www.| 欧美精品片 | 免费能直接在线观看黄的视频 | 成人h视频在线观看 | 国产1区2区3区 | 天天综合干 | 做a视频 | 午夜成人免费视频 | 福利av在线| 国产在线视频一区二区董小宛性色 | 国产成人在线观看免费 | 午夜免费在线观看 | 国产片网站 | 日日干夜夜草 | 成人性生交a做片 | 天堂成人av | 国产精品美女久久久久aⅴ国产馆 | 久久久久91 | 国产成人精品一区二区 | 精品久久久久久亚洲综合网 | www.4虎影院 国产999精品久久久影片官网 | 久操伊人 |