真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

go語言gc例子 go 語言 gui

Golang實(shí)驗(yàn)性功能SetMaxHeap 固定值GC

簡單來說, SetMaxHeap 提供了一種可以設(shè)置固定觸發(fā)閾值的 GC (Garbage Collection垃圾回收)方式

成都創(chuàng)新互聯(lián)公司專注于企業(yè)成都全網(wǎng)營銷推廣、網(wǎng)站重做改版、鐘樓網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5技術(shù)商城系統(tǒng)網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為鐘樓等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

官方源碼鏈接

大量臨時(shí)對象分配導(dǎo)致的 GC 觸發(fā)頻率過高, GC 后實(shí)際存活的對象較少,

或者機(jī)器內(nèi)存較充足,希望使用剩余內(nèi)存,降低 GC 頻率的場景

GC 會 STW ( Stop The World ),對于時(shí)延敏感場景,在一個(gè)周期內(nèi)連續(xù)觸發(fā)兩輪 GC ,那么 STW 和 GC 占用的 CPU 資源都會造成很大的影響, SetMaxHeap 并不一定是完美的,在某些場景下做了些權(quán)衡,官方也在進(jìn)行相關(guān)的實(shí)驗(yàn),當(dāng)前方案仍沒有合入主版本。

先看下如果沒有 SetMaxHeap ,對于如上所述的場景的解決方案

這里簡單說下 GC 的幾個(gè)值的含義,可通過 GODEBUG=gctrace=1 獲得如下數(shù)據(jù)

這里只關(guān)注 128-132-67 MB 135 MB goal ,

分別為 GC開始時(shí)內(nèi)存使用量 - GC標(biāo)記完成時(shí)內(nèi)存使用量 - GC標(biāo)記完成時(shí)的存活內(nèi)存量 本輪GC標(biāo)記完成時(shí)的 預(yù)期 內(nèi)存使用量(上一輪 GC 完成時(shí)確定)

引用 GC peace設(shè)計(jì)文檔 中的一張圖來說明

對應(yīng)關(guān)系如下:

簡單說下 GC pacing (信用機(jī)制)

GC pacing 有兩個(gè)目標(biāo),

那么當(dāng)一輪 GC 完成時(shí),如何只根據(jù)本輪 GC 存活量去實(shí)現(xiàn)這兩個(gè)小目標(biāo)呢?

這里實(shí)際是根據(jù)當(dāng)前的一些數(shù)據(jù)或狀態(tài)去 預(yù)估 “未來”,所有會存在些誤差

首先確定 gc Goal goal = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100

heap_marked 為本輪 GC 存活量, gcpercent 默認(rèn)為 100 ,可以通過環(huán)境變量 GOGC=100 或者 debug.SetGCPercent(100) 來設(shè)置

那么默認(rèn)情況下 goal = 2 * heap_marked

gc_trigger 是與 goal 相關(guān)的一個(gè)值( gc_trigger 大約為 goal 的 90% 左右),每輪 GC 標(biāo)記完成時(shí),會根據(jù) |Ha-Hg| 和實(shí)際使用的 cpu 資源 動態(tài)調(diào)整 gc_trigger 與 goal 的差值

goal 與 gc_trigger 的差值即為,為 GC 期間分配的對象所預(yù)留的空間

GC pacing 還會預(yù)估下一輪 GC 發(fā)生時(shí),需要掃描對象對象的總量,進(jìn)而換算為下一輪 GC 所需的工作量,進(jìn)而計(jì)算出 mark assist 的值

本輪 GC 觸發(fā)( gc_trigger ),到本輪的 goal 期間,需要盡力完成 GC mark 標(biāo)記操作,所以當(dāng) GC 期間,某個(gè) goroutine 分配大量內(nèi)存時(shí),就會被拉去做 mark assist 工作,先進(jìn)行 GC mark 標(biāo)記賺取足夠的信用值后,才能分配對應(yīng)大小的對象

根據(jù)本輪 GC 存活的內(nèi)存量( heap_marked )和下一輪 GC 觸發(fā)的閾值( gc_trigger )計(jì)算 sweep assist 的值,本輪 GC 完成,到下一輪 GC 觸發(fā)( gc_trigger )時(shí),需要盡力完成 sweep 清掃操作

預(yù)估下一輪 GC 所需的工作量的方式如下:

繼續(xù)分析文章開頭的問題,如何充分利用剩余內(nèi)存,降低 GC 頻率和 GC 對 CPU 的資源消耗

如上圖可以看出, GC 后,存活的對象為 2GB 左右,如果將 gcpercent 設(shè)置為 400 ,那么就可以將下一輪 GC 觸發(fā)閾值提升到 10GB 左右

前面一輪看起來很好,提升了 GC 觸發(fā)的閾值到 10GB ,但是如果某一輪 GC 后的存活對象到達(dá) 2.5GB 的時(shí)候,那么下一輪 GC 觸發(fā)的閾值,將會超過內(nèi)存閾值,造成 OOM ( Out of Memory ),進(jìn)而導(dǎo)致程序崩潰。

可以通過 GOGC=off 或者 debug.SetGCPercent(-1) 來關(guān)閉 GC

可以通過進(jìn)程外監(jiān)控內(nèi)存使用狀態(tài),使用信號觸發(fā)的方式通知程序,或 ReadMemStats 、或 linkname runtime.heapRetained 等方式進(jìn)行堆內(nèi)存使用的監(jiān)測

可以通過調(diào)用 runtime.GC() 或者 debug.FreeOSMemory() 來手動進(jìn)行 GC 。

這里還需要說幾個(gè)事情來解釋這個(gè)方案所存在的問題

通過 GOGC=off 或者 debug.SetGCPercent(-1) 是如何關(guān)閉 GC 的?

gc 4 @1.006s 0%: 0.033+5.6+0.024 ms clock, 0.27+4.4/11/25+0.19 ms cpu, 428-428-16 MB, 17592186044415 MB goal, 8 P (forced)

通過 GC trace 可以看出,上面所說的 goal 變成了一個(gè)很詭異的值 17592186044415

實(shí)際上關(guān)閉 GC 后, Go 會將 goal 設(shè)置為一個(gè)極大值 ^uint64(0) ,那么對應(yīng)的 GC 觸發(fā)閾值也被調(diào)成了一個(gè)極大值,這種處理方式看起來也沒什么問題,將閾值調(diào)大,預(yù)期永遠(yuǎn)不會再觸發(fā) GC

那么如果在關(guān)閉 GC 的情況下,手動調(diào)用 runtime.GC() 會導(dǎo)致什么呢?

由于 goal 和 gc_trigger 被設(shè)置成了極大值, mark assist 和 sweep assist 也會按照這個(gè)錯(cuò)誤的值去計(jì)算,導(dǎo)致工作量預(yù)估錯(cuò)誤,這一點(diǎn)可以從 trace 中進(jìn)行證明

可以看到很詭異的 trace 圖,這里不做深究,該方案與 GC pacing 信用機(jī)制不兼容

記住,不要在關(guān)閉 GC 的情況下手動觸發(fā) GC ,至少在當(dāng)前 Go1.14 版本中仍存在這個(gè)問題

SetMaxHeap 的實(shí)現(xiàn)原理,簡單來說是強(qiáng)行控制了 goal 的值

注: SetMaxHeap ,本質(zhì)上是一個(gè)軟限制,并不能解決 極端場景 下的 OOM ,可以配合內(nèi)存監(jiān)控和 debug.FreeOSMemory() 使用

SetMaxHeap 控制的是堆內(nèi)存大小, Go 中除了堆內(nèi)存還分配了如下內(nèi)存,所以實(shí)際使用過程中,與實(shí)際硬件內(nèi)存閾值之間需要留有一部分余量。

對于文章開始所述問題,使用 SetMaxHeap 后,預(yù)期的 GC 過程大概是這個(gè)樣子

簡單用法1

該方法簡單粗暴,直接將 goal 設(shè)置為了固定值

注:通過上文所講,觸發(fā) GC 實(shí)際上是 gc_trigger ,所以當(dāng)閾值設(shè)置為 12GB 時(shí),會提前一點(diǎn)觸發(fā) GC ,這里為了描述方便,近似認(rèn)為 gc_trigger=goal

簡單用法2

當(dāng)不關(guān)閉 GC 時(shí), SetMaxHeap 的邏輯是, goal 仍按照 gcpercent 進(jìn)行計(jì)算,當(dāng) goal 小于 SetMaxHeap 閾值時(shí)不進(jìn)行處理;當(dāng) goal 大于 SetMaxHeap 閾值時(shí),將 goal 限制為 SetMaxHeap 閾值

注:通過上文所講,觸發(fā) GC 實(shí)際上是 gc_trigger ,所以當(dāng)閾值設(shè)置為 12GB 時(shí),會提前一點(diǎn)觸發(fā) GC ,這里為了描述方便,近似認(rèn)為 gc_trigger=goal

切換到 go1.14 分支,作者選擇了 git checkout go1.14.5

選擇官方提供的 cherry-pick 方式(可能需要梯子,文件改動不多,我后面會列出具體改動)

git fetch "" refs/changes/67/227767/3 git cherry-pick FETCH_HEAD

需要重新編譯Go源碼

注意點(diǎn):

下面源碼中的官方注釋說的比較清楚,在一些關(guān)鍵位置加入了中文注釋

入?yún)ytes為要設(shè)置的閾值

notify 簡單理解為 GC 的策略 發(fā)生變化時(shí)會向 channel 發(fā)送通知,后續(xù)源碼可以看出“策略”具體指哪些內(nèi)容

返回值為本次設(shè)置之前的 MaxHeap 值

$GOROOT/src/runtime/debug/garbage.go

$GOROOT/src/runtime/mgc.go

注:作者盡量用通俗易懂的語言去解釋 Go 的一些機(jī)制和 SetMaxHeap 功能,可能有些描述與實(shí)現(xiàn)細(xì)節(jié)不完全一致,如有錯(cuò)誤還請指出

go語言可以做什么

1、服務(wù)器編程:以前你如果使用C或者C++做的那些事情,用Go來做很合適,例如處理日志、數(shù)據(jù)打包、虛擬機(jī)處理、文件系統(tǒng)等。

2、分布式系統(tǒng)、數(shù)據(jù)庫代理器、中間件:例如Etcd。

3、網(wǎng)絡(luò)編程:這一塊目前應(yīng)用最廣,包括Web應(yīng)用、API應(yīng)用、下載應(yīng)用,而且Go內(nèi)置的net/http包基本上把我們平常用到的網(wǎng)絡(luò)功能都實(shí)現(xiàn)了。

4、開發(fā)云平臺:目前國外很多云平臺在采用Go開發(fā),我們所熟知的七牛云、華為云等等都有使用Go進(jìn)行開發(fā)并且開源的成型的產(chǎn)品。

5、區(qū)塊鏈:目前有一種說法,技術(shù)從業(yè)人員把Go語言稱作為區(qū)塊鏈行業(yè)的開發(fā)語言。如果大家學(xué)習(xí)區(qū)塊鏈技術(shù)的話,就會發(fā)現(xiàn)現(xiàn)在有很多很多的區(qū)塊鏈的系統(tǒng)和應(yīng)用都是采用Go進(jìn)行開發(fā)的,比如ehtereum是目前知名度最大的公鏈,再比如fabric是目前最知名的聯(lián)盟鏈,兩者都有g(shù)o語言的版本,且go-ehtereum還是以太坊官方推薦的版本。

自1.0版發(fā)布以來,go語言引起了眾多開發(fā)者的關(guān)注,并得到了廣泛的應(yīng)用。go語言簡單、高效、并發(fā)的特點(diǎn)吸引了許多傳統(tǒng)的語言開發(fā)人員,其數(shù)量也在不斷增加。

使用 Go 語言開發(fā)的開源項(xiàng)目非常多。早期的 Go 語言開源項(xiàng)目只是通過 Go 語言與傳統(tǒng)項(xiàng)目進(jìn)行C語言庫綁定實(shí)現(xiàn),例如 Qt、Sqlite 等。

后期的很多項(xiàng)目都使用 Go 語言進(jìn)行重新原生實(shí)現(xiàn),這個(gè)過程相對于其他語言要簡單一些,這也促成了大量使用 Go 語言原生開發(fā)項(xiàng)目的出現(xiàn)。

Go語言能做什么?

Go 語言被設(shè)計(jì)成一門應(yīng)用于搭載 Web 服務(wù)器,存儲集群或類似用途的巨型中央服務(wù)器的系統(tǒng)編程語言。對于高性能分布式系統(tǒng)領(lǐng)域而言,Go 語言無疑比大多數(shù)其它語言有著更高的開發(fā)效率。學(xué)習(xí)Go語言,可以說是很簡單的,入門快,想學(xué)習(xí)Go語言,可以到黑馬程序員看看,有新出的教程。

Golang什么時(shí)候會觸發(fā)GC

Golang采用了三色標(biāo)記法來進(jìn)行垃圾回收,那么在什么場景下會觸發(fā)這個(gè)回收動作呢?

源碼主要位于文件 src/runtime/mgc.go go version 1.16

觸發(fā)條件從大方面說,可分為 手動觸發(fā) 和 系統(tǒng)觸發(fā) 兩種方式。手動觸發(fā)一般很少用,主要由開發(fā)者通過調(diào)用 runtime.GC() 函數(shù)來實(shí)現(xiàn),而對于系統(tǒng)自動觸發(fā)是 運(yùn)行時(shí) 根據(jù)一些條件判斷來進(jìn)行的,這也正是本文要介紹的內(nèi)容。

不管哪種觸發(fā)方式,底層回收機(jī)制是一樣的,所以我們先看一下手動觸發(fā),根據(jù)它來找系統(tǒng)觸發(fā)的條件。

可以看到開始執(zhí)行GC的是 gcStart() 函數(shù),它有一個(gè) gcTrigger 參數(shù),是一個(gè)觸發(fā)條件結(jié)構(gòu)體,它的結(jié)構(gòu)體也很簡單。

其實(shí)在Golang 內(nèi)部所有的GC都是通過 gcStart() 函數(shù),然后指定一個(gè) gcTrigger 的參數(shù)來開始的,而手動觸發(fā)指定的條件值為 gcTriggerCycle 。 gcStart 是一個(gè)很復(fù)雜的函數(shù),有興趣的可以看一下源碼實(shí)現(xiàn)。

對于 kind 的值有三種,分別為 gcTriggerHeap 、 gcTriggerTime 和 gcTriggerCycle 。

運(yùn)行時(shí)會通過 gcTrigger.test() 函數(shù)來決定是否需要觸發(fā)GC,只要滿足上面基中一個(gè)即可。

到此我們基本明白了這三種觸發(fā)GC的條件,那么對于系統(tǒng)自動觸發(fā)這種,Golang 從一個(gè)程序的開始到運(yùn)行,它又是如何一步一步監(jiān)控到這個(gè)條件的呢?

其實(shí) runtime 在程序啟動時(shí),會在一個(gè)初始化函數(shù) init() 里啟用一個(gè) forcegchelper() 函數(shù),這個(gè)函數(shù)位于 proc.go 文件。

為了減少系統(tǒng)資源占用,在 forcegchelper 函數(shù)里會通過 goparkunlock() 函數(shù)主動讓自己陷入休眠,以后由 sysmon() 監(jiān)控線程根據(jù)條件來恢復(fù)這個(gè)gc goroutine。

可以看到 sysmon() 會在一個(gè) for 語句里一直判斷這個(gè) gcTriggerTime 這個(gè)條件是否滿足,如果滿足的話,會將 forcegc.g 這個(gè) goroutine 添加到全局隊(duì)列里進(jìn)行調(diào)度(這里 forcegc 是一個(gè)全局變量)。

調(diào)度器在調(diào)度循環(huán) runtime.schedule 中還可以通過垃圾收集控制器的 runtime.gcControllerState.findRunnabledGCWorker 獲取并執(zhí)行用于后臺標(biāo)記的任務(wù)。


分享名稱:go語言gc例子 go 語言 gui
文章網(wǎng)址:http://weahome.cn/article/ddddhce.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部