简谈Go语言致命错误退出进程场景

252 阅读2分钟

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
...