go panic和c++ coredump差不多, 來看看go panic.
看程式:
package main
import "fmt"
func main() {
fmt.Println("main begin")
var p *int
*p = 0
fmt.Println("main end")
for {}
}
結果:
main begin
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1090f33]
goroutine 1 [running]:
main.main()
/Users/xxx/test/a.go:7 +0x63
exit status 2
可見,panic後,程序退出了。
再看:
package main
import "fmt"
import "runtime/debug"
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("haha")
debug.PrintStack()
}
}()
fmt.Println("main begin")
var p *int
*p = 0
fmt.Println("main end")
for {}
}
結果:
main begin
haha
goroutine 1 [running]:
runtime/debug.Stack(0xc00000c018, 0xc000076de8, 0x1)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.main.func1()
/Users/xxx/test/a.go:9 +0x82
panic(0x10a9620, 0x115d520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.main()
/Users/xxx/test/a.go:16 +0x83
程序還是退出了,可見在main中recover并沒有什麼卵用。
再看:
package main
import "fmt"
import "runtime/debug"
func fun() {
defer func() {
if err := recover(); err != nil {
fmt.Println("haha")
debug.PrintStack()
}
}()
fmt.Println("fun begin")
var p *int
*p = 0
fmt.Println("fun end")
}
func main() {
fmt.Println("main begin")
fun()
fmt.Println("main end")
for {}
}
結果:
main begin
fun begin
haha
goroutine 1 [running]:
runtime/debug.Stack(0xc00008c008, 0xc000082d88, 0x1)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
/Users/xxx/test/a.go:9 +0x82
panic(0x10a96e0, 0x115d520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.fun()
/Users/xxx/test/a.go:15 +0x83
main.main()
/Users/xxx/test/a.go:22 +0x66
main end
可見,在fun層panic後退出了,沒有被for{}卡住,但在main層沒有退出,被for{}卡住了, 程序還是活着的。
那好,現在來看看:
package main
import "fmt"
import "runtime/debug"
func high() {
fmt.Println("high begin")
middle()
fmt.Println("high end")
}
func middle() {
fmt.Println("middle begin")
low()
var p *int
*p = 0
fmt.Println("middle end")
}
func low() {
fmt.Println("low begin")
fmt.Println("low end")
}
func fun() {
fmt.Println("fun begin")
defer func() {
debug.PrintStack()
}()
fmt.Println("yyy")
high()
fmt.Println("zzz")
fmt.Println("fun end")
for {}
}
func main() {
fmt.Println("main begin")
fun()
a := 2
b := 3
fmt.Println("main end", a * b)
for {}
}
結果:
main begin
fun begin
yyy
high begin
middle begin
low begin
low end
goroutine 1 [running]:
runtime/debug.Stack(0x0, 0x10, 0x8)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
/Users/xxx/test/a.go:28 +0x20
panic(0x10a9a00, 0x115e520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.middle()
/Users/xxx/test/a.go:15 +0x68
main.high()
/Users/xxx/test/a.go:7 +0x66
main.fun()
/Users/xxx/test/a.go:32 +0xc6
main.main()
/Users/xxx/test/a.go:42 +0x66
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1091528]
goroutine 1 [running]:
main.middle()
/Users/xxx/test/a.go:15 +0x68
main.high()
/Users/xxx/test/a.go:7 +0x66
main.fun()
/Users/xxx/test/a.go:32 +0xc6
main.main()
/Users/xxx/test/a.go:42 +0x66
exit status 2
很顯然,沒有recover去處理panic資訊,是以整個程序崩潰, 如下:
再來看看:
package main
import "fmt"
import "runtime/debug"
func high() {
fmt.Println("high begin")
middle()
fmt.Println("high end")
}
func middle() {
fmt.Println("middle begin")
low()
var p *int
*p = 0
fmt.Println("middle end")
}
func low() {
fmt.Println("low begin")
fmt.Println("low end")
}
func fun() {
fmt.Println("fun begin")
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
}
}()
fmt.Println("yyy")
high()
fmt.Println("zzz")
fmt.Println("fun end")
for {}
}
func main() {
fmt.Println("main begin")
fun()
a := 2
b := 3
fmt.Println("main end", a * b)
for {}
}
結果:
main begin
fun begin
yyy
high begin
middle begin
low begin
low end
goroutine 1 [running]:
runtime/debug.Stack(0x115e5c0, 0xc000042c00, 0x0)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
/Users/xxx/test/a.go:29 +0x42
panic(0x10a9a20, 0x115e520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.middle()
/Users/xxx/test/a.go:15 +0x68
main.high()
/Users/xxx/test/a.go:7 +0x66
main.fun()
/Users/xxx/test/a.go:34 +0xc6
main.main()
/Users/xxx/test/a.go:44 +0x66
main end 6
可以看到middle層有panic, 故提前異常退出middle, high和fun, 但在fun層被recover了,是以main層仍然正常,整個程序不會崩潰,仍然活得好好的。
最後看看,如何擷取堆棧資訊的串呢? 且看:
package main
import "fmt"
import "runtime/debug"
func fun() {
fmt.Println("fun begin")
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
fmt.Println("xxx", string(debug.Stack()))
}
}()
var p *int
*p = 0
fmt.Println("fun end")
for {}
}
func main() {
fmt.Println("main begin")
fun()
fmt.Println("main end")
for {}
}
結果:
main begin
fun begin
goroutine 1 [running]:
runtime/debug.Stack(0xc000088060, 0xc00009a000, 0xa)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:16 +0x22
main.fun.func1()
/Users/xxx/test/a.go:10 +0x46
panic(0x10a9760, 0x115d520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.fun()
/Users/xxx/test/a.go:16 +0x7f
main.main()
/Users/xxx/test/a.go:24 +0x66
xxx goroutine 1 [running]:
runtime/debug.Stack(0xc00007ada8, 0x10a9760, 0x115d520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/debug/stack.go:24 +0xa7
main.fun.func1()
/Users/xxx/test/a.go:11 +0x4b
panic(0x10a9760, 0x115d520)
/usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:513 +0x1b9
main.fun()
/Users/xxx/test/a.go:16 +0x7f
main.main()
/Users/xxx/test/a.go:24 +0x66
main end
總之,panic觸發層到recover層都會異常退出。 但recover層之上不會異常退出。
不多說。