[TOC]
# 簡介
命令`go env`用于打印Go語言的環境信息。其中的一些信息我們在之前已經多次提及,但是卻沒有進行詳細的說明。在本小節,我們會對這些信息進行深入介紹。我們先來看一看`go env`命令情況下都會打印出哪些Go語言通用環境信息。
`go env`命令可打印出的Go語言通用環境信息

~~~
> runtime 包 包含與 Go 的運行時系統交互的操作,例如控制 goroutines 的函數。
> 也包含 reflect 包使用的低級別的類型信息;查看 reflect 的文檔了解運行時類型的可編程接口。
> 以下環境變量($name 或 %name% 取決于主機操作系統)控制 Go 程序的運行時行為,其含義和用途可能會隨版本發布而變化
~~~
# GOGC
`GOGC`變量設置初始垃圾收集目標百分比。
當新分配的數據與上一次收集后剩余的活動數據的比率達到此百分比時,將觸發收集。
默認值為`GOGC = 100`。
設置`GOGC = off`會完全禁用垃圾收集器。
`runtime/debug`包的`SetGCPercent`函數允許在運行時更改此百分比。
# GODEBUG
`GODEBUG`變量控制運行時內的調試變量。
它是以逗號分隔的`name = val`對列表,用于設置這些命名變量:
~~~
allocfreetrace:設置 `allocfreetrace = 1` 會導致對每個對象的分配和釋放進行概要分析和棧跟蹤。
clobberfree:設置 `clobberfree = 1` 使垃圾回收器在釋放對象時用錯誤內容破壞對象的內存內容。
cgocheck:
設置 `cgocheck = 0` 禁用使用 cgo 將 Go 指針錯誤傳遞到非 Go 代碼的所有包檢查。
設置 `cgocheck = 1`(默認值)可以啟用相對便宜的檢查,這些檢查可能會遺漏一些錯誤。
設置 `cgocheck = 2` 啟用昂貴的檢查,這些檢查不會遺漏任何錯誤,但是會導致程序運行速度變慢。
efence:
設置 `efence = 1` 會導致分配器以某種模式運行,在該模式下每個對象都分配在一個唯一的頁面上,地址永遠不會被回收。
gccheckmark:
設置 `gccheckmark = 1` 可以通過在 STW 時執行第二次標記傳遞來驗證垃圾收集器的并發標記階段。
如果第二次傳遞找到了一個并發標記未找到的可達對象,垃圾收集器將 panic。
gcpacertrace:設置 `gcpacertrace = 1` 會導致垃圾收集器打印有關并發 pacer 內部狀態的信息。
gcshrinkstackoff:
設置 `gcshrinkstackoff = 1` 禁止將 goroutines 移動到較小的棧上。
在這種模式下,goroutine 的棧只能增長。
gcstoptheworld:
設置 `gcstoptheworld = 1` 禁用并發垃圾收集,使每個垃圾收集成為一個 STW 事件。
設置 `gcstoptheworld = 2` 還會在垃圾收集完成后禁用并發清除。
~~~
~~~
gctrace:
設置 `gctrace = 1` 會導致垃圾收集器在每次收集時向標準錯誤輸出發出一行,
匯總收集的內存量和暫停的長度。此行的格式可能會發生變化。
目前格式是:
gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P
其中字段含義如下('#' 代表數字):
gc # 每次 GC 時遞增的 GC 編號
@#s 程序運行的秒數
#% 自程序啟動后在 GC 中花費的時間百分比
#+...+# GC 各階段的掛鐘時間(wall-clock)/CPU 時間
#->#-># MB GC 開始時的堆大小、GC 結束時的堆大小和活動堆大小
# MB goal 目標堆大小
# P 使用的處理器數量
這些階段是 stop-the-world(STW)清除終止(sweep termination),
并發標記和掃描,以及 STW 標記終止(mark termination)。
`mark/scan` 的 CPU 時間被分解為輔助時間(根據分配執行的 GC)、后臺 GC 時間和空閑 GC 時間。
如果該行以 `"(forced)"` 結尾,則此 GC 由 `runtime.GC()` 調用強制執行。
~~~
**掛鐘時間:**
根據計算機的內部時鐘流逝的時間,這應該與外界的時間相匹配。
這與 CPU 使用率無關; 它僅供參考。
如果掛鐘時間 < CPU 時間,那么您正在并行執行一個程序。
如果掛鐘時間 > CPU時間,則表示您正在等待磁盤,網絡或其他設備。
~~~
將 `gctrace` 設置為任何大于 0 的值也會導致垃圾收集器在將內存釋放回系統時發出摘要。
將內存返回到系統的這個過程稱為清除(`scavenging`)。
此摘要的格式可能會更改。
目前格式是:
scvg#: # MB released printed only if non-zero
scvg#: inuse: # idle: # sys: # released: # consumed: # (MB)
其中字段含義如下('#' 代表數字):
scvg# 清除周期數,每次清除時遞增
inuse: # MB 已使用或部分使用的 spans
idle: # MB spans 待清除
sys: # 從系統映射的 MB
released: # 釋放到系統的 MB
consumed: # 從系統中分配的 MB
~~~
~~~
madvdontneed:
設置 madvdontneed = 1 當將內存返回到內核時,將在 Linux 上使用 MADV_DONTNEED 而不是 MADV_FREE。
這效率較低,但會導致 RSS(resident set size 常駐內存集)數量下降得更快。
~~~
madvise() ?系統調用允許一個了解其內存行為的進程將其描述給系統,給予使用內存的建議。
**int
madvise(void \*addr, size\_t len, int advice);**
系統可以使用傳入的建議來更改其虛擬內存分頁策略。
此建議可以提高應用程序和系統性能。建議有很多種其中兩種:
**MADV\_DONTNEED:**
表示應用程序不希望很快訪問此地址范圍。
**MADV\_FREE:**
表示應用程序不需要此地址范圍中包含的信息,因此可以立即重用這些頁面。
地址范圍仍然有效。
~~~
memprofilerate:
設置 `memprofilerate = X` 將更新 runtime.MemProfileRate 的值。
設置為 0 時,禁用內存分析。
MemProfileRate 控制在內存概要文件中記錄和報告的內存分配比例。
分析器的目標是對每 `MemProfileRate` 字節的平均分配進行抽樣。
要在概要文件中包含每個已分配的塊,請將 `MemProfileRate` 設置為 1。
要完全關閉分析,請將 `MemProfileRate` 設置為 0。
處理內存概要文件的工具假設概要文件速率在程序的整個生命周期中是恒定的,并且等于當前值。
更改內存分析速率的程序應該只改變一次,在程序執行過程中越早越好(例如,在 `main` 的開頭)。
var MemProfileRate int = 512 * 1024
~~~
----
~~~
invalidptr:
默認 `invalidptr = 1`,如果在指針類型的位置中發現無效的指針值(例如,1),
則會導致垃圾收集器和棧復制器使程序 crash。
設置 `invalidptr = 0` 將禁用此檢查。
這應該只被用作診斷錯誤代碼的臨時解決方案。
真正的解決方案是不將整數存儲在指針類型的位置。
~~~
~~~
sbrk:
設置 `sbrk = 1` 用一個簡單的分配器替換內存分配器和垃圾收集器,
該分配器從操作系統獲取內存并且永遠不會回收任何內存。
~~~
* * *
~~~
scavenge:
`scavenge = 1` 啟用堆清除程序的調試模式。
~~~
* * *
~~~
scheddetail:
設置 `schedtrace = X` 和 `scheddetail = 1` 會導致調度程序每 `X` 毫秒發出一次詳細的多行信息,
描述`調度程序`,`處理器`,`線程` 和 `goroutines` 的狀態。
schedtrace:
設置 `schedtrace = X` 使調度程序每 `X` 毫秒發出一行標準錯誤,匯總調度程序狀態。
~~~
* * *
~~~
tracebackancestors:
設置 `tracebackancestors = N` 使用創建 `goroutines` 的棧擴展回溯,
其中 `N` 限制要報告的祖先 `goroutines` 的數量。
這也擴展了 `runtime.Stack` 返回的信息。
祖先的 `goroutine IDs` 將引用創建時 goroutine 的 ID;
這個 ID 有可能被重用于另一個 goroutine。
將 `N` 設置為 0 將不報告任何祖先信息。
~~~
`net`,`net/http`和`crypto/tls`?也引用`GODEBUG`中的調試變量
# GOMAXPROCS
`GOMAXPROCS`變量限制了可以同時執行用戶級 Go 代碼的操作系統線程數
(即,可以同時執行的最大`CPU`數)。
代表 Go 代碼在系統調用中可以阻塞的線程數沒有限制;那些不計入`GOMAXPROCS`限制。
該包的`GOMAXPROCS`函數查詢并更改限制。
# GOTRACEBACK
`GOTRACEBACK`變量控制 Go 程序因未恢復的`panic`或意外的運行時條件而失敗時生成的輸出量。
默認情況下,失敗會打印當前`goroutine`的棧跟蹤,省略運行時系統內部的函數,然后使用退出代碼`2`退出。
如果當前`goroutine`或者故障都不在運行時內部,則故障會打印所有`goroutines`的棧跟蹤。
* `GOTRACEBACK = none`完全省略了 goroutine 棧跟蹤。
* `GOTRACEBACK = single`(默認值)的行為如上所述。
* `GOTRACEBACK = all`為用戶創建的所有 goroutines 添加棧跟蹤。
* `GOTRACEBACK=system`就像`"all"`,但為運行時函數添加了棧幀,并顯示了運行時內部創建的 goroutine。
* `GOTRACEBACK=crash`就像`"system"`,但是以特定于操作系統的方式 crash 而不是退出。例如,在`Unix`系統上,`crash`引發`SIGABRT`以觸發核心轉儲(`core dump`)。
由于歷史原因,`GOTRACEBACK`設置`0`,`1`和`2`分別是`none`,`all`和`system`的同義詞。
`runtime/debug`包的`SetTraceback`函數允許在運行時增加輸出量,但不能減少到低于環境變量指定的輸出量
# **CGO\_ENABLED**
通過上一小節的介紹,相信讀者對cgo工具已經很熟悉了。我們提到過,標準go命令可以自動的使用cgo工具對導入了代碼包C的代碼包和源碼文件進行處理。這里所說的“自動”并不是絕對的。因為當環境變量CGO\_ENABLED被設置為0時,標準go命令就不能處理導入了代碼包C的代碼包和源碼文件了。請看下面的示例:
~~~
hc@ubt:~/golang/goc2p/src/basic/cgo$ export CGO_ENABLED=0
hc@ubt:~/golang/goc2p/src/basic/cgo$ go build -x
WORK=/tmp/go-build775234613
~~~
我們臨時把環境變量CGO\_ENABLED的值設置為0,然后執行`go build`命令并加入了標記`-x`。標記`-x`會讓命令程序將運行期間所有實際執行的命令都打印到標準輸出。但是,在執行命令之后沒有任何命令被打印出來。這說明對代碼包`basic/cgo`的構建操作并沒有被執行。這是因為,構建這個代碼包需要用到cgo工具,但cgo工具已經被禁用了。下面,我們再來運行調用了代碼包`basic/cgo`中函數的命令源碼文件cgo\_demo.go。也就是說,命令源碼文件cgo\_demo.go間接的導入了代碼包`C`。還記得嗎?這個命令源碼文件被存放在goc2p項目的代碼包`basic/cgo`中。示例如下:
~~~
hc@ubt:~/golang/goc2p/src/basic/cgo$ export CGO_ENABLED=0
hc@ubt:~/golang/goc2p/src/basic/cgo$ go run -work cgo_demo.go
WORK=/tmp/go-build856581210
# command-line-arguments
./cgo_demo.go:4: can't find import: "basic/cgo/lib"
~~~
在上面的示例中,我們在執行`go run`命令時加入了兩個標記——`-a`和`-work`。標記`-a`會使命令程序強行重新構建所有的代碼包(包括涉及到的標準庫),即使它們已經是最新的了。標記`-work`會使命令程序將臨時工作目錄的絕對路徑打印到標準輸出。命令程序輸出的錯誤信息顯示,命令程序沒有找到代碼包`basic/cgo`。其原因是由于代碼包`basic/cgo`無法被構建。所以,命令程序在臨時工作目錄和工作區中都找不到代碼包basic/cgo對應的歸檔文件cgo.a。如果我們使用命令`ll /tmp/go-build856581210`查看臨時工作目錄,也找不到名為basic的目錄。
不過,如果我們在環境變量CGO\_ENABLED的值為1的情況下生成代碼包`basic/cgo`對應的歸檔文件cgo.a,那么無論我們之后怎樣改變環境變量CGO\_ENABLED的值也都可以正確的運行命令源碼文件cgo\_demo.go。即使我們在執行`go run`命令時加入標記`-a`也是如此。因為命令程序依然可以在工作區中找到之前在我們執行`go install`命令時生成的歸檔文件cgo.a。示例如下:
~~~
hc@ubt:~/golang/goc2p/src/basic/cgo$ export CGO_ENABLED=1
hc@ubt:~/golang/goc2p/src/basic/cgo$ go install ../basic/cgo
hc@ubt:~/golang/goc2p/src/basic/cgo$ export CGO_ENABLED=0
hc@ubt:~/golang/goc2p/src/basic/cgo$ go run -a -work cgo_demo.go
WORK=/tmp/go-build130612063
The square root of 2.330000 is 1.526434.
ABC
CFunction1() is called.
GoFunction1() is called.
~~~
由此可知,只要我們事先成功安裝了引用了代碼包C的代碼包,即生成了對應的代碼包歸檔文件,即使cgo工具在之后被禁用,也不會影響到其它Go語言代碼對該代碼包的使用。當然,命令程序首先會到臨時工作目錄中尋找需要的代碼包歸檔文件。
關于cgo工具還有一點需要特別注意,即:**當存在交叉編譯的情況時,cgo工具一定是不可用的**。在標準go命令的上下文環境中,交叉編譯意味著程序構建環境的目標計算架構的標識與程序運行環境的目標計算架構的標識不同,或者程序構建環境的目標操作系統的標識與程序運行環境的目標操作系統的標識不同。在這里,我們可以粗略認為交叉編譯就是在當前的計算架構和操作系統下編譯和構建Go語言代碼并生成針對于其他計算架構或/和操作系統的編譯結果文件和可執行文件。
# **GOARCH**
GOARCH的值的含義是程序構建環境的目標計算架構的標識,也就是程序在構建或安裝時所對應的計算架構的名稱。在默認情況下,它會與程序運行環境的目標計算架構一致。即它的值會與GOHOSTARCH的值是相同。但如果我們顯式的設置了環境變量GOARCH,則它的值就會是這個環境變量的值。
# **GOBIN**
GOBIN的值為存放可執行文件的目錄的絕對路徑。它的值來自環境變量GOBIN。在我們使用`go tool install`命令安裝命令源碼文件時生成的可執行文件會存放于這個目錄中。
# **GOCHAR**
GOCHAR的值是程序構建環境的目標計算架構的單字符標識。它的值會根據GOARCH的值來設置。當GOARCH的值為386時,GOCHAR的值就是8。當GOARCH的值為amd64時GOCHAR的值就是6。而GOCHAR的值5與GOARCH的值arm相對應。
GOCHAR主要有兩個用途,列舉如下:
1. Go語言官方的平臺相關的工具的名稱會以它的值為前綴。的名稱會以GOCHAR的值為前綴。比如,在amd64計算架構下,用于編譯Go語言代碼的編譯器的名稱是6g,鏈接器的名稱是6l。用于編譯C語言代碼的編譯器的名稱是6c。而用于編譯匯編語言代碼的編譯器的名稱為6a。
2. Go語言的官方編譯器生成的結果文件會以GOCHAR的值作為擴展名。Go語言的官方編譯器6g在對命令源碼文件編譯之后會把結果文件*go*.6存放到臨時工作目錄的相應位置中。
# **GOEXE**
GOEXE的值會被作為可執行文件的后綴。它的值與GOOS的值存在一定關系,即只有GOOS的值為“windows”時GOEXE的值才會是“.exe”,否則其值就為空字符串“”。這與在各個操作系統下的可執行文件的默認后綴是一致的。
# **GOHOSTARCH**
GOHOSTARCH的值的含義是程序運行環境的目標計算架構的標識,也就是程序在運行時所在的計算機系統的計算架構的名稱。在通常情況下,它的值不需要被顯式的設置。因為用來安裝Go語言的二進制分發文件和MSI(Microsoft軟件安裝)軟件包文件都是平臺相關的。所以,對于不同計算架構的Go語言環境來說,它都會是一個常量。
# **GOHOSTOS**
GOHOSTOS的值的含義是程序運行環境的目標操作系統的標識,也即程序在運行時所在的計算機系統的操作系統的名稱。與GOHOSTARCH類似,它的值在不同的操作系統下是固定不變的,同樣不需要顯式的設置。
# **GOPATH**
這個環境信息我們在之前已經提到過很多次。它的值指明了Go語言工作區目錄的絕對路徑。我們需要顯式的設置環境變量GOPATH。如果有多個工作區,那么多個工作區的絕對路徑之間需要用分隔符分隔。在windows操作系統下,這個分隔符為“;”。在其它操作系統下,這個分隔符為“:”。注意,GOPATH的值不能與GOROOT的值相同。
# **GORACE**
GORACE的值包含了用于數據競爭檢測的相關選項。數據競爭是在并發程序中最常見和最難調試的一類bug。數據競爭會發生在多個Goroutine爭相訪問相同的變量且至少有一個Goroutine中的程序在對這個變量進行寫操作的情況下。
數據競爭檢測需要被顯式的開啟。還記得標記`-race`嗎?我們可以通過在執行一些標準go命令時加入這個標記來開啟數據競爭檢測。在這種情況下,GORACE的值就會被使用到了。支持`-race`標記的標準go命令包括:`go test`命令、`go run`命令、`go build`命令和`go install`命令。
GORACE的值形如“option1=val1 option2=val2”,即:選項名稱與選項值之間以等號“=”分隔,多個選項之間以空格“ ”分隔。數據競爭檢測的選項包括log\_path、exitcode、strip\_path\_prefix和history\_size。為了設置GORACE的值,我們需要設置環境變量GORACE。或者,我們也可以在執行go命令時臨時設置它,像這樣:
~~~
hc@ubt:~/golang/goc2p/src/cnet/ctcp$ GORACE="log_path=/home/hc/golang/goc2p /race/report strip_path_prefix=home/hc/golang/goc2p/" go test -race
~~~
關于數據競爭檢測的更多細節我們將會在本書的第三部分予以說明。
# **GOROOT**
GOROOT會是我們在安裝Go語言時第一個碰到Go語言環境變量。它的值指明了Go語言的安裝目錄的絕對路徑。但是,只有在非默認情況下我們才需要顯式的設置環境變量GOROOT。這里所說的默認情況是指:在Windows操作系統下我們把Go語言安裝到c:\\Go目錄下,或者在其它操作系統下我們把Go語言安裝到/usr/local/go目錄下。另外,當我們不是通過二進制分發包來安裝Go語言的時候,也不需要設置環境變量GOROOT的值。比如,在Windows操作系統下,我們可以使用MSI軟件包文件來安裝Go語言。
# **GOTOOLDIR**
GOTOOLDIR的值指明了Go工具目錄的絕對路徑。根據GOROOT、GOHOSTOS和GOHOSTARCH來設置。其值為$GOROOT/pkg/tool/$GOOS\_$GOARCH。關于這個目錄,我們在之前也提到過多次。
除了上面介紹的這些通用的Go語言環境信息,還兩個針對于非Plan 9操作系統的環境信息。它們是CC和GOGCCFLAGS。環境信息CC的值是操作系統默認的C語言編譯器的命令名稱。環境信息GOGCCFLAGS的值則是Go語言在使用操作系統的默認C語言編譯器對C語言代碼進行編譯時加入的參數。
如果我們要有針對性的查看上述的一個或多個環境信息,可以在`go env`命令的后面加入它們的名字并執行之。在`go env`命令和環境信息名稱之間需要用空格分隔,多個環境信息名稱之間也需要用空格分隔。示例如下:
~~~
hc@ubt:~$ go env GOARCH GOCHAR
386
8
~~~
上例的`go env`命令的輸出信息中,每一行對一個環境信息的值,且其順序與我們輸入的環境信息名稱的順序一致。比如,386為環境信息GOARCH,而8則是環境信息GOCHAR的值。
`go env`命令能夠讓我們對當前的Go語言環境進行簡要的了解。通過它,我們也可以對當前安裝的Go語言的環境設置進行簡單的檢查。
- 基礎
- 簡介
- 主要特征
- 變量和常量
- 編碼轉換
- 數組
- byte與rune
- big
- sort接口
- 和mysql類型對應
- 函數
- 閉包
- 工作區
- 復合類型
- 指針
- 切片
- map
- 結構體
- sync.Map
- 隨機數
- 面向對象
- 匿名組合
- 方法
- 接口
- 權限
- 類型查詢
- 異常處理
- error
- panic
- recover
- 自定義錯誤
- 字符串處理
- 正則表達式
- json
- 文件操作
- os
- 文件讀寫
- 目錄
- bufio
- ioutil
- gob
- 棧幀的內存布局
- shell
- 時間處理
- time詳情
- time使用
- new和make的區別
- container
- list
- heap
- ring
- 測試
- 單元測試
- Mock依賴
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 詳解
- plugin包
- 信號
- goto
- 協程
- 簡介
- 創建
- 協程退出
- runtime
- channel
- select
- 死鎖
- 互斥鎖
- 讀寫鎖
- 條件變量
- 嵌套
- 計算單個協程占用內存
- 執行規則
- 原子操作
- WaitGroup
- 定時器
- 對象池
- sync.once
- 網絡編程
- 分層模型
- socket
- tcp
- udp
- 服務端
- 客戶端
- 并發服務器
- Http
- 簡介
- http服務器
- http客戶端
- 爬蟲
- 平滑重啟
- context
- httptest
- 優雅中止
- web服務平滑重啟
- beego
- 安裝
- 路由器
- orm
- 單表增刪改查
- 多級表
- orm使用
- 高級查詢
- 關系查詢
- SQL查詢
- 元數據二次定義
- 控制器
- 參數解析
- 過濾器
- 數據輸出
- 表單數據驗證
- 錯誤處理
- 日志
- 模塊
- cache
- task
- 調試模塊
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密碼
- 對稱加密
- 非對稱加密
- 單向散列函數
- 消息認證
- 數字簽名
- mysql優化
- 常見錯誤
- go run的錯誤
- 新手常見錯誤
- 中級錯誤
- 高級錯誤
- 常用工具
- 協程-泄露
- go env
- gometalinter代碼檢查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高編譯
- go get
- 代理
- 其他的知識
- go內存對齊
- 細節總結
- nginx路由匹配
- 一些博客
- redis為什么快
- cpu高速緩存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密碼加密解密
- for 循環迭代變量
- 備注
- 垃圾回收
- 協程和纖程
- tar-gz
- 紅包算法
- 解決golang.org/x 下載失敗
- 逃逸分析
- docker
- 鏡像
- 容器
- 數據卷
- 網絡管理
- 網絡模式
- dockerfile
- docker-composer
- 微服務
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell調用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb