panic源码解读

前言

go version go1.13.15 darwin/amd64

panic的作用

panicpanicGoroutinedeferrecoverpanicdefer

举个栗子

输出

1
2
panic: 3

goroutine 1 [running]:
main.main.func1(...)
        /Users/yj/Go/src/Go-POINT/panic/main.go:9
main.main()
        /Users/yj/Go/src/Go-POINT/panic/main.go:10 +0xee

panic

对于recover

  • panic只会触发当前Goroutine的defer;
  • recover只有在defer中调用才会生效;
  • panic允许在defer中嵌套多次调用;
recoverpanicgoroutine

嵌套的demo

输出

in main
panic: 1 panic once
        panic: 2 panic again
        panic: 3 panic again and again

goroutine 1 [running]:
...

panicdeferdefer

panic使用场景

  • error:可预见的错误
  • panic:不可预见的异常
errorpanicrecoverpanicrecover
panic

1、发生了一个不能恢复的错误,此时程序不能继续运行。 一个例子就是 web 服务器无法绑定所要求的端口。在这种情况下,就应该使用 panic,因为如果不能绑定端口,啥也做不了。

2、发生了一个编程上的错误。 假如我们有一个接收指针参数的方法,而其他人使用 nil 作为参数调用了它。在这种情况下,我们可以使用panic,因为这是一个编程错误:用 nil 参数调用了一个只能接收合法指针的方法。

在一般情况下,我们不应通过调用panic函数来报告普通的错误,而应该只把它作为报告致命错误的一种方式。当某些不应该发生的场景发生时,我们就应该调用panic。

panic

1、空指针引用

2、下标越界

3、除数为0

4、不应该出现的分支,比如default

5、输入不应该引起函数错误

看下实现

_panic
linkgoroutinepanic

gopanic

panicgopanic
runtime._panicGoroutinepanic
_deferruntime._deferruntime.reflectcall
runtime.fatalpanic

梳理下流程

panicpanicpanic
  • 系统栈上的panic无法恢复
  • 如果正在进行malloc时发生panic也无法恢复
  • 在禁止抢占时发生panic也无法恢复
  • 在g锁在m上时发生panic也无法恢复
panicpaniclinkgoroutinepanic
goroutinedefer
recoverpanicruntime.deferprocruntime.deferreturnruntime.deferturnpanicruntime.gorecoverruntime._panicpanicarg
recoverygsppcgogoggrecovergoroutinerecovery
recoverpanicruntime.deferprocruntime.deferreturnruntime.deferturnpanicruntime.gorecoverruntime._panicpanicarg

gorecover

recovergorecover
recovergorecoverrecovered
runtime._panicrecoveredruntime.gorecoverruntime.gopanic
gorecoverrecoveredgopanicmcallrecovery

fatalpanic

runtime.fatalpanicruntime.printpanicspanic

总结

引一段来自【panic 和recover】的总结

1、编译器会负责做转换关键字的工作;

panicrecoverruntime.gopanicruntime.gorecover
deferruntime.deferproc
deferruntime.deferreturn
runtime.gopanicGoroutineruntime._defer
runtime.gorecover_panic.recoveredtruepanic
runtime.gopanicruntime._deferpcspruntime.recovery
runtime.recoverypcspruntime.deferproc
runtime.deferproc0runtime.deferreturn
runtime.gorecoverruntime._deferruntime.fatalpanicpanic2

参考

【panic 和 recover】https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-panic-recover/
【恐慌与恢复内建函数】https://golang.design/under-the-hood/zh-cn/part1basic/ch03lang/panic/
【Go语言panic/recover的实现】https://zhuanlan.zhihu.com/p/72779197
【panic and recover】https://eddycjy.gitbook.io/golang/di-6-ke-chang-yong-guan-jian-zi/panic-and-recover
【翻了源码,我把 panic 与 recover 给彻底搞明白了】https://jishuin.proginn.com/p/763bfbd4ed8c