關(guān)于go語言stw的實(shí)例的信息

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

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

成都創(chuàng)新互聯(lián)從2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站建設(shè)、成都網(wǎng)站制作網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元扶風(fēng)做網(wǎng)站,已為上家服務(wù),為扶風(fēng)各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-86922220

官方源碼鏈接

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

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

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

先看下如果沒有 SetMaxHeap ,對(duì)于如上所述的場(chǎng)景的解決方案

這里簡(jiǎn)單說下 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ì)文檔 中的一張圖來說明

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

簡(jiǎ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ù)估 “未來”,所有會(huì)存在些誤差

首先確定 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í),會(huì)根據(jù) |Ha-Hg| 和實(shí)際使用的 cpu 資源 動(dòng)態(tài)調(diào)整 gc_trigger 與 goal 的差值

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

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

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

根據(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 對(duì) CPU 的資源消耗

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

前面一輪看起來很好,提升了 GC 觸發(fā)的閾值到 10GB ,但是如果某一輪 GC 后的存活對(duì)象到達(dá) 2.5GB 的時(shí)候,那么下一輪 GC 觸發(fā)的閾值,將會(huì)超過內(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),使用信號(hào)觸發(fā)的方式通知程序,或 ReadMemStats 、或 linkname runtime.heapRetained 等方式進(jìn)行堆內(nèi)存使用的監(jiān)測(cè)

可以通過調(diào)用 runtime.GC() 或者 debug.FreeOSMemory() 來手動(dòng)進(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 會(huì)將 goal 設(shè)置為一個(gè)極大值 ^uint64(0) ,那么對(duì)應(yīng)的 GC 觸發(fā)閾值也被調(diào)成了一個(gè)極大值,這種處理方式看起來也沒什么問題,將閾值調(diào)大,預(yù)期永遠(yuǎn)不會(huì)再觸發(fā) GC

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

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

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

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

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

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

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

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

簡(jiǎn)單用法1

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

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

簡(jiǎn)單用法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í),會(huì)提前一點(diǎn)觸發(fā) GC ,這里為了描述方便,近似認(rèn)為 gc_trigger=goal

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

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

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

需要重新編譯Go源碼

注意點(diǎn):

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

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

notify 簡(jiǎn)單理解為 GC 的策略 發(fā)生變化時(shí)會(huì)向 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ò)誤還請(qǐng)指出

go的垃圾回收算法

從Gov1.12版本開始,Go使用了非分代的、并發(fā)的、基于三色標(biāo)記清除的垃圾回收器。

關(guān)于垃圾回收,比較常見的算法有引用計(jì)數(shù)、標(biāo)記清除和分代收集,Golang語言使用的垃圾回收算法是標(biāo)記清除。

Golang語言的標(biāo)記清除垃圾回收算法,為了防止GC掃描時(shí)內(nèi)存變化引起的混亂。那么就需要 STW,即Stop The World。具體在Golang語言中是指,在GC時(shí)先停止所有g(shù)oroutine。再進(jìn)行垃圾回收,等待垃圾回收結(jié)束后再恢復(fù)所有被停止的goroutine。

標(biāo)記清除方法

啟動(dòng)STW,暫停程序的業(yè)務(wù)邏輯,找出不可達(dá)對(duì)象和可達(dá)對(duì)象。

將所有可達(dá)對(duì)象做標(biāo)記,清除未標(biāo)記的對(duì)象。停止STW,程序繼續(xù)執(zhí)行。循環(huán)往復(fù),直到進(jìn)程程序生命周期結(jié)束。因?yàn)镾TW需要暫停程序,為了減少暫停程序的時(shí)間。將清除操作移出 STW執(zhí)行周期,但是優(yōu)化效果不明顯。

所謂三色標(biāo)記,實(shí)際上只是為了方便敘述而抽象出來的一種說法,三色對(duì)應(yīng)垃圾回收過程中對(duì)象的三種狀態(tài)。白色是對(duì)象未被標(biāo)記,gcmarkBits對(duì)應(yīng)位為0,該對(duì)象將會(huì)在本次GC中被清理?;疑菍?duì)象還在標(biāo)記隊(duì)列中等待被標(biāo)記,黑色是對(duì)象已被標(biāo)記,gcmarkBits對(duì)應(yīng)位為0,該對(duì)象將會(huì)在本次 GC中被回收。

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ā)云平臺(tái):目前國(guó)外很多云平臺(tái)在采用Go開發(fā),我們所熟知的七牛云、華為云等等都有使用Go進(jìn)行開發(fā)并且開源的成型的產(chǎn)品。

5、區(qū)塊鏈:目前有一種說法,技術(shù)從業(yè)人員把Go語言稱作為區(qū)塊鏈行業(yè)的開發(fā)語言。如果大家學(xué)習(xí)區(qū)塊鏈技術(shù)的話,就會(huì)發(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語言簡(jiǎn)單、高效、并發(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è)過程相對(duì)于其他語言要簡(jiǎn)單一些,這也促成了大量使用 Go 語言原生開發(fā)項(xiàng)目的出現(xiàn)。

go語言聊天室實(shí)現(xiàn)(六)創(chuàng)建HTTP連接,并升級(jí)為長(zhǎng)連接

我們?cè)趍ian函數(shù)中,首先初始化配置文件,然后新建http連接。

這個(gè)連接創(chuàng)建之后,監(jiān)聽服務(wù)器的9999端口。如果url的路徑后綴為 "/ws",就轉(zhuǎn)發(fā)到ws/ws.go中的IndexHandler方法中。

這個(gè)方法中首先我們創(chuàng)建一個(gè)websocket的Upgrader實(shí)例,然后我們使用Upgrader的upgrade方法來升級(jí)一下我們的連接為長(zhǎng)連接。

升級(jí)完成之后會(huì)返回一個(gè)*websocket.Conn的連接,我們之后所有的關(guān)于連接的操作,都是基于該conn的。

在該連接完成之后,我們將連接存放到一個(gè)名為Client的map中,以便之后管理更為方便。

之后,我們啟動(dòng)一個(gè)goroutine來讀取連接中發(fā)送的信息內(nèi)容,再根據(jù)內(nèi)容進(jìn)行相應(yīng)的操作。

網(wǎng)站名稱:關(guān)于go語言stw的實(shí)例的信息
文章鏈接:http://www.muchs.cn/article2/ddijjoc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)品牌網(wǎng)站制作、網(wǎng)站設(shè)計(jì)公司、微信公眾號(hào)、關(guān)鍵詞優(yōu)化定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)