激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術(shù)及教程分享平臺!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Golang - 談?wù)揋o 什么時候會觸發(fā) GC問題

談?wù)揋o 什么時候會觸發(fā) GC問題

2021-11-17 11:50煎魚 Golang

Go 語言作為一門新語言,在早期經(jīng)常遭到唾棄的就是在垃圾回收(下稱:GC)機制中 STW(Stop-The-World)的時間過長。下面文章就對此話題展開,感興趣的小伙伴可以參考下面文章的內(nèi)容

在早期經(jīng)常遭到唾棄的就是在垃圾回收(下稱:GC)機制中 STW(Stop-The-World)的時間過長。那么這個時候,我們又會好奇一點,作為 STW 的起始,Go 語言中什么時候才會觸發(fā) GC 呢?

1、什么是 GC

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

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

2、為什么要 GC

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

3、GC 觸發(fā)場景

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

  • 系統(tǒng)觸發(fā):運行時自行根據(jù)內(nèi)置的條件,檢查、發(fā)現(xiàn)到,則進行 GC 處理,維護整個應(yīng)用程序的可用性。
  • 手動觸發(fā):開發(fā)者在業(yè)務(wù)代碼中自行調(diào)用 runtime.GC 方法來觸發(fā) GC 行為。

3.1系統(tǒng)觸發(fā)

在系統(tǒng)觸發(fā)的場景中,Go 源碼的 src/runtime/mgc.go 文件,明確標(biāo)識了 GC 系統(tǒng)觸發(fā)的三種場景,分別如下:

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

在手動觸發(fā)的 runtime.GC 方法中涉及。

3.2手動觸發(fā)

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

談?wù)揋o 什么時候會觸發(fā) GC問題

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

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

3.3 基本流程

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

核心代碼如下:

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

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

開始新的一輪 GC 周期,調(diào)用 gcStart 方法觸發(fā) GC 行為,開始掃描標(biāo)記階段。

需要調(diào)用 gcWaitOnMark 方法等待,直到當(dāng)前 GC 周期的掃描、標(biāo)記、標(biāo)記終止完成。

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

在本輪 GC 已經(jīng)基本完成后,會調(diào)用 mProf_PostSweep 方法。以此記錄最后一次標(biāo)記終止時的堆配置文件快照。

結(jié)束,釋放 M。

3.4 在哪觸發(fā)

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

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

4、監(jiān)控線程

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

代碼如下:

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

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

在休眠后,會由 sysmon 這一個系統(tǒng)監(jiān)控線程來進行監(jiān)控、喚醒等行為:

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

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

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

5、堆內(nèi)存申請

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

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

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

小對象:如果申請小對象時,發(fā)現(xiàn)當(dāng)前內(nèi)存空間不存在空閑跨度時,將會需要調(diào)用 nextFree 方法獲取新的可用的對象,可能會觸發(fā) GC 行為。

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

總結(jié)
在這篇文章中,我們介紹了 Go 語言觸發(fā) GC 的兩大類場景,并分別基于大類中的細(xì)分場景進行了一一說明。

到此這篇關(guān)于談?wù)揋o 什么時候會觸發(fā) GC問題的文章就介紹到這了,更多相關(guān)Go 什么時候會觸發(fā) GC?內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://www.tuicool.com/articles/2aua2mf

延伸 · 閱讀

精彩推薦
  • Golanggolang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggo日志系統(tǒng)logrus顯示文件和行號的操作

    go日志系統(tǒng)logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統(tǒng)logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang如何使用struct的tag屬性的詳細(xì)介紹

    golang如何使用struct的tag屬性的詳細(xì)介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細(xì)介紹,從例子說起,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網(wǎng)11352020-05-21
  • GolangGolang通脈之?dāng)?shù)據(jù)類型詳情

    Golang通脈之?dāng)?shù)據(jù)類型詳情

    這篇文章主要介紹了Golang通脈之?dāng)?shù)據(jù)類型,在編程語言中標(biāo)識符就是定義的具有某種意義的詞,比如變量名、常量名、函數(shù)名等等,Go語言中標(biāo)識符允許由...

    4272021-11-24
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • GolangGolang中Bit數(shù)組的實現(xiàn)方式

    Golang中Bit數(shù)組的實現(xiàn)方式

    這篇文章主要介紹了Golang中Bit數(shù)組的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang的httpserver優(yōu)雅重啟方法詳解

    golang的httpserver優(yōu)雅重啟方法詳解

    這篇文章主要給大家介紹了關(guān)于golang的httpserver優(yōu)雅重啟的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,...

    helight2992020-05-14
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
主站蜘蛛池模板: 中文字幕在线免费播放 | 欧美va亚洲 | 成人三级免费电影 | 性欧美videos另类极品 | 午夜视频国产 | 成人国产精品久久久 | 午夜生活理论片 | 播色网 | 国产精品视频成人 | 粉嫩av一区二区三区四区在线观看 | 亚洲一区在线观看视频 | 手机国产乱子伦精品视频 | 欧美极品欧美精品欧美视频 | 色播视频在线播放 | 性片网站 | 国产精品刺激对白麻豆99 | 精品一区二区三区电影 | 久久人人av| 国产精品久久久久久久久久大牛 | 欧美一级免费高清 | 黄色小视频免费在线观看 | 成人午夜精品久久久久久久3d | 一级做a爱片毛片免费 | 欧美成人性色 | 国产精品99爱 | 成人毛片免费 | 在线成人免费av | 成人在线视频免费 | 国产精品久久久久久久久久久天堂 | 国产日韩一区二区三区在线观看 | 羞羞的| 久久国产成人午夜av浪潮 | 一级免费| 免费a级观看| 久久久久久久99 | 国产精品一区99 | 中文字幕国 | 激情小说激情电影 | 成人在线国产 | 午夜视频你懂的 | 成人h精品动漫一区二区三区 |