1. 程式人生 > >Go 語言執行時環境變數快速導覽

Go 語言執行時環境變數快速導覽

原文: http://dave.cheney.net/2015/11/29/a-whirlwind-tour-of-gos-runtime-environment-variables


Go 語言執行時環境變數快速導覽

Go Runtime除了提供:GC, goroutine排程, 定時器,network polling等服務外, 還提供其它一些工具設施,用於開啟額外的除錯輸出, 

或是改變Go Runtime自身的一些行為。這些工具設施由傳給Go program的一些環境變數控制, 本文主要講述它們。


GOGC


GOGC 是Go Runtime最早支援的環境變數,甚至比GOROOT還早,幾乎無人不知。GOGC 用於控制GC的處發頻率, 其值預設為100, 

意為直到自上次垃圾回收後heap size已經增長了100%時GC才觸發執行。即是GOGC=100意味著live heap size 每增長一倍,GC觸發執行一次。

如設定GOGC=200, 則live heap size 自上次垃圾回收後,增長2倍時,GC觸發執行, 總之,其值越大則GC觸發執行頻率越低, 反之則越高,

 如果GOGC=off 則關閉GC.

雖然go 1.5引入了低延遲的GC, 但是GOGC對GC執行頻率的影響不變, 仍然是其值大於100,則越大GC執行頻率越高,
反之則越低。


GOTRACEBACK


GOTRACEBACK用於控制當異常發生時,系統提供資訊的詳細程度, 在go 1.5, GOTRACEBACK有4個值。
 

  • GOTRACEBACK=0 只輸出panic異常資訊。
  • GOTRACEBACK=1 此為go的預設設定值, 輸出所有goroutine的stack traces, 除去與go runtime相關的stack frames.
  • GOTRACEBACK=2 在GOTRACEBACK=1的基礎上, 還輸出與go runtime相關的stack frames,從而瞭解哪些goroutines是由go runtime啟動執行的。
  • GOTRACEBACK=crash, 在GOTRACEBACK=2的基礎上,go runtime處發進程segfault錯誤,從而生成core dump, 當然要作業系統允許的情況下, 而不是呼叫os.Exit。


以下為GOTRACEBACK的程式碼測試例子
 

package main

func main() {
    panic("kerboom")
}

執行結果:

$ env GOTRACEBACK=0 ./crash 
panic: kerboom
$ echo $?
2


讀者有興趣可以嘗試其它值, 看看效果。


GOTRACEBACK


在go 1.6中的變化

  • GOTRACEBACK=none 只輸出panic異常資訊。
  • GOTRACEBACK=single 只輸出被認為引發panic異常的那個goroutine的相關資訊。
  • GOTRACEBACK=all 輸出所有goroutines的相關資訊,除去與go runtime相關的stack frames.
  • GOTRACEBACK=system 輸出所有goroutines的相關資訊,包括與go runtime相關的stack frames,從而得知哪些goroutine是go runtime啟動執行的。
  • GOTRACEBACK=crash 與go 1.5相同, 未變化。


為了與go 1.5相容,0 對應 none, 1 對應 all, 以及 2 對應 system.

注意: 在go 1.6中, 預設,只輸出引發panci異常的goroutine的stack trace.



GOMAXPROCS


GOMAXPROCS 大家比較熟悉, 用於控制作業系統的執行緒數量, 這些執行緒用於執行go程式中的goroutines.
到go 1.5的時候, GOMAXPROCS的預設值就是我們的go程式啟動時可見的作業系統認為的CPU個數。


注意: 在我們的go程式中使用的作業系統執行緒數量,也包括:正服務於cgo calls的執行緒, 阻塞於作業系統calls的執行緒,
所以go 程式中使用的作業系統執行緒數量可能大於GOMAXPROCS的值。
 

GODEBUG


老鼠拉鐵鍬,大頭在後邊, 本文其餘篇幅主要講講GODEBUG. GODEBUG的值被解釋為一個個的
name=value對, 每一對間由逗號分割,每一對用於控制go runtime 除錯工具設施, 例如:

$ env GODEBUG=gctrace=1,schedtrace=1000 godoc -http=:8080

上面這條命令用於執行godoc程式時開啟 GC tracing and schedule tracing.


下面開始介紹幾個比較有用的除錯工具設施



gctrace


這個工具我認為最有用處了,請看程式輸出便知

$ env GODEBUG=gctrace=1 godoc -http=:8080 -index
gc #1 @0.042s 4%: 0.051+1.1+0.026+16+0.43 ms clock, 0.10+1.1+0+2.0/6.7/0+0.86 ms cpu, 4->32->10 MB, 4 MB goal, 4 P
gc #2 @0.062s 5%: 0.044+1.0+0.017+2.3+0.23 ms clock, 0.044+1.0+0+0.46/2.0/0+0.23 ms cpu, 4->12->3 MB, 8 MB goal, 4 P
gc #3 @0.067s 6%: 0.041+1.1+0.078+4.0+0.31 ms clock, 0.082+1.1+0+0/2.8/0+0.62 ms cpu, 4->6->4 MB, 8 MB goal, 4 P
gc #4 @0.073s 7%: 0.044+1.3+0.018+3.1+0.27 ms clock, 0.089+1.3+0+0/2.9/0+0.54 ms cpu, 4->7->4 MB, 6 MB goal, 4 P

此資訊的輸出格式隨著go的每一不同的版本發生變化,但總是能發現共性的東西, 如: 每一GC 階段所花費的時間量, heap size 的變化量, 
也包括每一GC階段完成時間,相對於程式啟動時的時間,當然老版本go可能省略一些資訊。

每一行資訊都很有用, 不過我認為綜合分析這些資訊則更有用,比如, 不斷輸出的gc tracing,可以清楚在表明程式的記憶體分配情況, 

持續不斷增長的heap size 則表明可能有記憶體洩露,也許一些被引用的東西沒有被釋放。


開啟gctrace的代價是很小的,不過其通常是關閉的, 不過我推薦在一些產品環境中,抽取一些
樣本產品,開啟這個除錯工具。

原文未翻譯,未找到準確表述。
note:setting gctrace to values larger than 1 causes each garbage collection cycle to be run twice.
 This exercises some aspects of finalisation that require two garbage collection cycles to complete. 
 You should not use this as a mechanism to alter finalisation performance in your programs because you should not write programs who’s correctness depends on finalisation.

The heap scavenger

到目前為止,gctrace給出的最有用的資訊就是 the heap scavenger的輸出.
 

scvg143: inuse: 8, idle: 104, sys: 113, released: 104, consumed: 8 (MB)


scavenger 的工作就是週期性地打掃heap中無用的作業系統記憶體分頁, 它會向作業系統發出建義,請作業系統回收無用記憶體頁,

當然並不能強迫作業系統立刻就去做回收處理,作業系統可以忽略此建義,或是延遲迴收,比如直到可分配的空閒記憶體不夠的時候。


scavenger輸出的資訊是我們瞭解go程式虛擬記憶體空間使用情況的最好方式, 當然你也可以通過其它工具,如free, top來獲到這些資訊,
不過你應用信任scavenger.


schedtrace


因為go runtime管理著大量的goroutine, 並排程goroutine在作業系統執行緒集上執行,
這個作業系統執行緒集,其實是就是執行緒池, 所以從外部考察go程式的效能我們不能獲取足夠的細節資訊,
更談不上準確分析程式效能。故此我們需要直接瞭解go runtime scheduler的每一個操作,其輸出如下:

$ env GODEBUG=schedtrace=1000 godoc -http=:8080 -index
SCHED 0ms: gomaxprocs=4 idleprocs=2 threads=4 spinningthreads=1 idlethreads=0 runqueue=0 [0 0 0 0]
SCHED 1001ms: gomaxprocs=4 idleprocs=0 threads=8 spinningthreads=0 idlethreads=2 runqueue=0 [189 197 231 142]
SCHED 2004ms: gomaxprocs=4 idleprocs=0 threads=9 spinningthreads=0 idlethreads=1 runqueue=0 [54 45 38 86]
SCHED 3011ms: gomaxprocs=4 idleprocs=0 threads=9 spinningthreads=0 idlethreads=2 runqueue=2 [85 0 67 111]
SCHED 4018ms: gomaxprocs=4 idleprocs=3 threads=9 spinningthreads=0 idlethreads=4 runqueue=0 [0 0 0 0]

詳細討論請看 Dmitry Vyukov’s excellent blog post from the Intel DeveloperZone.

設定scheddetail=1將使go runtime輸出總結性資訊時, 一併輸出每一個goroutine的狀態資訊,如:
 

$ env GODEBUG=scheddetail=1,schedtrace=1000 godoc -http=:8080 -index
SCHED 0ms: gomaxprocs=4 idleprocs=3 threads=3 spinningthreads=0 idlethreads=0 runqueue=0 gcwaiting=0 nmidlelocked=0 stopwait=0 sysmonwait=0
  P0: status=1 schedtick=0 syscalltick=0 m=0 runqsize=0 gfreecnt=0
  P1: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
  P2: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
  P3: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
  M2: p=-1 curg=-1 mallocing=0 throwing=0 preemptoff= locks=1 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
  M1: p=-1 curg=17 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=false lockedg=17
  M0: p=0 curg=1 mallocing=0 throwing=0 preemptoff= locks=2 dying=0 helpgc=0 spinning=false blocked=false lockedg=1
  G1: status=2(stack growth) m=0 lockedm=0
  G17: status=3() m=1 lockedm=1
  G2: status=1() m=-1 lockedm=-1

  
 這個輸出對於除錯goroutines leaking很有幫助, 不過其它工具, 諸如:net/http/pprof 
 好像更有用一些。
 
 深入閱讀請看godoc for the runtime package.