Go程序偶然出现崩溃场景。
为此,作为一名 “成熟” 的 Go 工程师,需要保障自己程序的健壮性外,为此网上收集了一些致命的错误场景。
一起学习和规避这些致命场景。
3.1. 并发读写 map
func foo() {
m := map[string]int{}
go func() {
for {
m["pulsar消息"] = 1
}
}()
for {
_ = m["pulsar消息2"]
}
}
输出结果:
fatal error: concurrent map read and map write
goroutine 1 [running]:
runtime.throw(0x1078103, 0x21)
...
3.2. 堆栈内存耗尽
func foo() {
var f func(a [1000]int64)
f = func(a [1000]int64) {
f(a)
}
f([1000]int64{})
}
输出结果:
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0200e1bf0 stack=[0xc0200e0000, 0xc0400e0000]
fatal error: stack overflow
runtime stack:
runtime.throw(0x1074ba3, 0xe)
/usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:1117 +0x72
runtime.newstack()
...
3.3. 将 nil 函数作为 goroutine 启动
func foo() {
var f func()
go f()
}
输出结果:
fatal error: go of nil func value
goroutine 1 [running]:
main.foo()
...
3.4. goroutines 死锁
func foo() {
select {}
}
输出结果:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.foo()
...
3.5. 线程限制耗尽
如果你的 goroutines 被 IO 操作阻塞了,新的线程可能会被启动来执行你的其他 goroutines。
Go 的最大的线程数是有默认限制的,如果达到了这个限制,你的应用程序就会崩溃。
会出现如下输出结果:
fatal error: thread exhaustion
...
可以通过调用 runtime.SetMaxThreads 方法增大线程数,不过也需要考量是否程序有问题。
3.6. 超出可用内存
如果你执行的操作,例如:下载大文件等。导致应用程序占用内存过大,程序上涨,导致 OOM。
会出现如下输出结果:
fatal error: runtime: out of memory
...