1、取出記錄本登記使用者和開(kāi)始時(shí)間。
為海南州等地區(qū)用戶(hù)提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及海南州網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、海南州網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶(hù)提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶(hù)的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
2、打開(kāi)凈化器上的載氣開(kāi)關(guān)閥,然后檢查是否漏氣,保證氣密性良好。
3、調(diào)節(jié)腫瘤量為適當(dāng)值。
4、調(diào)節(jié)分流閥是分流流量為實(shí)驗(yàn)所需的流量,柱流量即為總流量減去分流量。
5、調(diào)節(jié)尾吹流量控制閥使尾吹流量為適當(dāng)值,并使尾吹流量與柱流量之和不低于載氣總流量。
6、打開(kāi)凈化器的空氣、氫氣開(kāi)關(guān)閥,調(diào)節(jié)空氣、氫氣流量為適當(dāng)值。
7、根據(jù)實(shí)驗(yàn)需要設(shè)置柱溫、進(jìn)樣口溫度和FID檢測(cè)器溫度。
8、FID檢測(cè)器溫度達(dá)到150攝氏度以上,按FIRE鍵點(diǎn)燃FID檢測(cè)器火焰。
9、設(shè)置FID檢測(cè)器靈敏度和輸出信號(hào)衰減。
10、如果基線(xiàn)不在零位,調(diào)節(jié)調(diào)零電位器A使FID輸出信號(hào)在紀(jì)錄儀或積分儀零位附近。待所設(shè)參數(shù)達(dá)到設(shè)置時(shí),即可進(jìn)行分析。
11、但所設(shè)參數(shù)達(dá)到設(shè)置時(shí)即可進(jìn)樣分析。
您好,要引起GC,首先要了解GC是什么。GC(垃圾回收)是一種自動(dòng)內(nèi)存管理機(jī)制,它可以自動(dòng)清理不再使用的內(nèi)存,以便釋放出可用的內(nèi)存空間。GC的主要目的是提高程序的性能,減少內(nèi)存泄漏,提高程序的可靠性。
要引起GC,可以通過(guò)以下幾種方式:
1. 內(nèi)存分配:如果程序中的內(nèi)存分配量過(guò)大,就會(huì)觸發(fā)GC,以釋放不再使用的內(nèi)存空間。
2. 內(nèi)存占用:如果程序中的內(nèi)存占用量過(guò)大,就會(huì)觸發(fā)GC,以釋放不再使用的內(nèi)存空間。
3. 內(nèi)存泄漏:如果程序中存在內(nèi)存泄漏,就會(huì)觸發(fā)GC,以釋放不再使用的內(nèi)存空間。
4. 程序運(yùn)行時(shí)間:如果程序運(yùn)行時(shí)間較長(zhǎng),就會(huì)觸發(fā)GC,以釋放不再使用的內(nèi)存空間。
5. 程序暫停:如果程序暫停,就會(huì)觸發(fā)GC,以釋放不再使用的內(nèi)存空間。
總之,GC的觸發(fā)機(jī)制主要是內(nèi)存分配量、內(nèi)存占用量、內(nèi)存泄漏、程序運(yùn)行時(shí)間和程序暫停等。只要程序中出現(xiàn)以上情況,就會(huì)觸發(fā)GC,以釋放不再使用的內(nèi)存空間。
簡(jiǎn)單來(lái)說(shuō), SetMaxHeap 提供了一種可以設(shè)置固定觸發(fā)閾值的 GC (Garbage Collection垃圾回收)方式
官方源碼鏈接
大量臨時(shí)對(duì)象分配導(dǎo)致的 GC 觸發(fā)頻率過(guò)高, 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)前方案仍沒(méi)有合入主版本。
先看下如果沒(méi)有 SetMaxHeap ,對(duì)于如上所述的場(chǎng)景的解決方案
這里簡(jiǎn)單說(shuō)下 GC 的幾個(gè)值的含義,可通過(guò) GODEBUG=gctrace=1 獲得如下數(shù)據(jù)
這里只關(guān)注 128-132-67 MB 135 MB goal ,
分別為 GC開(kāi)始時(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ì)文檔 中的一張圖來(lái)說(shuō)明
對(duì)應(yīng)關(guān)系如下:
簡(jiǎn)單說(shuō)下 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ù)估 “未來(lái)”,所有會(huì)存在些誤差
首先確定 gc Goal goal = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
heap_marked 為本輪 GC 存活量, gcpercent 默認(rèn)為 100 ,可以通過(guò)環(huán)境變量 GOGC=100 或者 debug.SetGCPercent(100) 來(lái)設(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ù)分析文章開(kāi)頭的問(wèn)題,如何充分利用剩余內(nèi)存,降低 GC 頻率和 GC 對(duì) CPU 的資源消耗
如上圖可以看出, GC 后,存活的對(duì)象為 2GB 左右,如果將 gcpercent 設(shè)置為 400 ,那么就可以將下一輪 GC 觸發(fā)閾值提升到 10GB 左右
前面一輪看起來(lái)很好,提升了 GC 觸發(fā)的閾值到 10GB ,但是如果某一輪 GC 后的存活對(duì)象到達(dá) 2.5GB 的時(shí)候,那么下一輪 GC 觸發(fā)的閾值,將會(huì)超過(guò)內(nèi)存閾值,造成 OOM ( Out of Memory ),進(jìn)而導(dǎo)致程序崩潰。
可以通過(guò) GOGC=off 或者 debug.SetGCPercent(-1) 來(lái)關(guān)閉 GC
可以通過(guò)進(jìn)程外監(jiān)控內(nèi)存使用狀態(tài),使用信號(hào)觸發(fā)的方式通知程序,或 ReadMemStats 、或 linkname runtime.heapRetained 等方式進(jìn)行堆內(nèi)存使用的監(jiān)測(cè)
可以通過(guò)調(diào)用 runtime.GC() 或者 debug.FreeOSMemory() 來(lái)手動(dòng)進(jìn)行 GC 。
這里還需要說(shuō)幾個(gè)事情來(lái)解釋這個(gè)方案所存在的問(wèn)題
通過(guò) 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)
通過(guò) GC trace 可以看出,上面所說(shuō)的 goal 變成了一個(gè)很詭異的值 17592186044415
實(shí)際上關(guān)閉 GC 后, Go 會(huì)將 goal 設(shè)置為一個(gè)極大值 ^uint64(0) ,那么對(duì)應(yīng)的 GC 觸發(fā)閾值也被調(diào)成了一個(gè)極大值,這種處理方式看起來(lái)也沒(méi)什么問(wèn)題,將閾值調(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è)問(wèn)題
SetMaxHeap 的實(shí)現(xiàn)原理,簡(jiǎn)單來(lái)說(shuō)是強(qiáng)行控制了 goal 的值
注: SetMaxHeap ,本質(zhì)上是一個(gè)軟限制,并不能解決 極端場(chǎng)景 下的 OOM ,可以配合內(nèi)存監(jiān)控和 debug.FreeOSMemory() 使用
SetMaxHeap 控制的是堆內(nèi)存大小, Go 中除了堆內(nèi)存還分配了如下內(nèi)存,所以實(shí)際使用過(guò)程中,與實(shí)際硬件內(nèi)存閾值之間需要留有一部分余量。
對(duì)于文章開(kāi)始所述問(wèn)題,使用 SetMaxHeap 后,預(yù)期的 GC 過(guò)程大概是這個(gè)樣子
簡(jiǎn)單用法1
該方法簡(jiǎn)單粗暴,直接將 goal 設(shè)置為了固定值
注:通過(guò)上文所講,觸發(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 閾值
注:通過(guò)上文所講,觸發(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):
下面源碼中的官方注釋說(shuō)的比較清楚,在一些關(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
注:作者盡量用通俗易懂的語(yǔ)言去解釋 Go 的一些機(jī)制和 SetMaxHeap 功能,可能有些描述與實(shí)現(xiàn)細(xì)節(jié)不完全一致,如有錯(cuò)誤還請(qǐng)指出
1. 關(guān)于方法區(qū)即永久代的回收,永久代的回收有兩種:常量池中的常量,無(wú)用的類(lèi)信息,常量的回收很簡(jiǎn)單,沒(méi)有引用了就可以被回收。對(duì)于無(wú)用的類(lèi)進(jìn)行回收,必須保證以下幾點(diǎn):
1.1 類(lèi)的所有實(shí)例都已經(jīng)被回收。
1.2 加載類(lèi)的ClassLoader已經(jīng)被回收。
1.3 類(lèi)對(duì)象的Class對(duì)象沒(méi)有被引用(即沒(méi)有通過(guò)反射引用該類(lèi)的地方)。
1.4 永久代的回收并不是必須的,可以通過(guò)參數(shù)來(lái)設(shè)置是否對(duì)類(lèi)進(jìn)行回收。
2、Minor GC ,F(xiàn)ull GC 觸發(fā)條件
Minor GC觸發(fā)條件:當(dāng)Eden區(qū)滿(mǎn)時(shí),觸發(fā)Minor GC。
3. Full GC觸發(fā)條件:
3.1 調(diào)用System.gc時(shí),系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行
3.2 老年代空間不足
3.3 方法區(qū)空間不足
3.4 通過(guò)Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存
3.5 由Eden區(qū)、From Space區(qū)向To Space區(qū)復(fù)制時(shí),對(duì)象大小大于To Space可用內(nèi)存,則把該對(duì)象轉(zhuǎn)存到老年代,且老年代的可用內(nèi)存小于該對(duì)象大小。