【Golang】影响runtime行为的环境变量
在Go语言中,为了控制低级别的 runtime
行为,官方提供了一些环境变量,主要有:
GOGC
GODEBUG
GOMAXPROCS
GORACE
GOTRACEBACK
初次之外,还有用于编译期的 GOROOT
,GOPATH
,GOOS
和 GOARCH
,以及用于玩转SSA的 GOSSAFUNC
。
在 src/runtime/extern.go
文件中详细描述了这些环境变量的背景和意义。在调度器初始化阶段,解析环境变量并且把他们放进全局变量 envs
中。
1 | // The bootstrap sequence is: |
GOGC
GOGC
用于控制GC的触发频率,默认值是:100
,意思是直到上次垃圾回收堆内存上涨 100%
时触发 GC
。如果设置 GOGC=off
将彻底关闭 GC
。在运行时可以通过 debug.SetGCPercent
进行动态调整。
GODEBUG
GODEBUG
用于控制运行时中的调试参数,形式上是 ,
分割的键值对,例如:
GODEBUG=‘gctrace=1,inittrace=1’ go run main.go
在调度系统初始化的时候,首先解析环境变量,然后解析调试参数:
1 | // The bootstrap sequence is: |
调试参数解析结束之后,都保存在全局变量 dbgvars
中:
1 | // src/runtime/runtime1.go |
allocfreetrace
allocfreetrace=1
会对于每次的内存分配都会进行概要分析,并且在分配内存和释放时打印调用栈。
clobberfree
clobberfree=1
会使垃圾回收期在释放对象,破坏持有非法内容对象的内存。
cgocheck
设置 cgocheck=0
会禁用对错误传递Go指针到非Go代码的检查。cgocheck=1
(默认值)会开启相对简单的检查,这可能导致一些错误被忽略。cgocheck=2
会采取相对严格的校验规则,会导致程序运行较慢,但是不会遗漏错误。
efence
设置 efence=1
会让内存分配器在分配内存时将每个对象分配在唯一的内存页上,并且这个地址永远不会被回收。
gccheckmark
setting gccheckmark=1 enables verification of the garbage collector’s concurrent mark phase by performing a second mark pass while the world is stopped. If the second pass finds a reachable object that was not found by concurrent mark, the garbage collector will panic.
gcpacertrace
设置 gcpacertrace=1
会使垃圾回收器打印并发 pacer 的内部状态信息。
gcshrinkstackoff
设置 gcshrinkstackoff=1
进制 goroutine
缩栈,这种模式下,goroutine
的栈只能增长。
gcstoptheworld
设置 gcstoptheworld=1
将禁用并发 GC
,这样每次垃圾回收都会 STW
。gcstoptheworld=2
处禁用并发收集之外还会禁用后续的并发清扫。
gctrace
设置 gctrace=1
会在每次 GC
时,向标准错误输出一行信息,包括收集的总量,停顿的时长等。输出的格式可能会变,目前的格式如下:
gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P
每个字段的解释如下:
gc
:gc 的次数,随着每次垃圾回收自增;@#s
:程序的运行时间,单位是秒;#%
:从程序运行开始到当前GC
,花费在GC
上的时间占比;#+#+# ms clock
:GC
各个阶段占用的时间;,#+#/#/#+# ms cpu
:垃圾回收占用的CPU时间;#->#-># MB
:分别表示GC
开始,结束以及当前的堆内存大小;# MB goal
:当堆内存达到这个值时,触发下次GC
;# P
:P
的个数;
例如查看下面程序的 GC
信息:
1 | package main |
1 | root@b89af2baca14:/WORKDIR/gostudy/hello# GODEBUG='gctrace=1' go run main.go |
inittrace
设置 inittrace=1
会让 runtime
打印每个 package
初始化工作的信息,包括执行时间和内存申请信息。对于没有用户定义和编译器生成的初始化工作的包,作为插件加载时,不会有任何信息打印。信息格式目前如下:
init # @#ms, # ms clock, # bytes, # allocs
每个字段的意义如下:
init #
:包名;@# ms
:从程序开始启动到init执行时的时间,单位是毫秒;# clock
:包初始化工作耗时;bytes
:申请的堆内存大小;allocs
:内存申请次数;
madvdontneed
设置 madvdontneed=0
在linux系统,归还内存给操作系统时使用 MADV_FREE
而不是 MADV_DONTNEED
,这很高效,但是同时意味着 RSS
数量只会在系统压力较小时下降。
memprofilerate
设置 memprofilerate=X
会更新 runtime.MemProfileRate
的值,设置位0时,禁用内存分析功能。
1 | // MemProfileRate controls the fraction of memory allocations |
invalidptr
设置 invalidptr=1
(默认)会使垃圾回收和栈赋值在遇到无效指针是,让程序奔溃。nvalidptr=0
会禁用该检查,这应该仅仅用于临时的代码debug。
sbrk
设置 sbrk=1
会使用普通的内存申请器,这会直接从操作系统申请内存并且永不释放。
scavtrace
设置 scavtrace=1
会让运行时系统在每次 GC
周期打印还给操作系统的内存总量和预估物理内存利用量。目前的格式如下:
scav # # KiB work, # KiB total, #% util
scav #
:清扫周期;KiB work
:从上次到当前,归还给操作的内存总量;KiB total
:归还给操作系统的内存总量;#% util
:正在使用的所有未清理内存的比例;
如果该行信息以 (forced)
结束,那说明调用了 debug.FreeOSMemory()
。
scheddetail
设置 schedtrace=X
和 scheddetail=1
会让调度器每隔 X ms
打印调度器,处理器,线程和goroutine的状态。
tracebackancestors
setting tracebackancestors=N extends tracebacks with the stacks at which goroutines were created, where N limits the number of ancestor goroutines to report. This also extends the information returned by runtime.Stack. Ancestor’s goroutine IDs will refer to the ID of the goroutine at the time of creation; it’s possible for this ID to be reused for another goroutine. Setting N to 0 will report no ancestry information.
asyncpreemptoff
设置 asyncpreemptoff=1
会禁用基于信号的异步goroutine抢占。这会使一些循环不可抢占,这可能会延迟 GC
以及 goroutine
调度。这对于调试 GC
问题很有用,因为他禁用了用于异步 goroutine
抢占的保守栈扫描。
GOMAXPROCS
GOMAXPROCS
限制用于同时执行用户代码的线程数量,Go语言中没有限制阻塞在系统调用的线程的数量,这些线程不计入 GOMAXPROCS
的限制。runtime.GOMAXPROCS 可以在运行时对此进行修改,一般情况下和系统的逻辑CPU数量相同。
GORACE
该环境变量用于配置数据竞争检测器,在程序构建时可以使用 -race
标记,https://go.dev/doc/articles/race_detector 这里有详细描述。
GOTRACEBACK
GOTRACEBACK
变量控制当 Go
程序由于未恢复的恐慌或意外的运行时条件而失败时生成的信息。默认情况下,失败打印当前 goroutine
的堆栈跟踪,省略运行时系统内部的函数,然后以退出代码 2
退出。如果没有当前 goroutine 或者是运行时内部失败,会打印所有 goroutine
信息。
GOTRACEBACK=none
省略整个goroutine
栈;GOTRACEBACK=single (默认)
和上面描述的一样;GOTRACEBACK=all
相比之前的会增加所有用户创建的goroutine
栈;GOTRACEBACK=system
在all
的基础之上,会增加运行时函数的栈帧,并且显示内部创建的gorotuine
;GOTRACEBACK=crash
和system
类似, 但以特定于操作系统的方式崩溃而不是退出。例如,在Unix
系统上,崩溃会引发SIGABRT
以触发核心转储;