【Go笔记】异常与异常捕获
特性
panic
执行的时候程序并不会直接异常退出,而是会终止当前函数的正常执行,执行defer
并逐层返回- 逐层返回的过程中,上层函数中,调用语句接下来的代码都不会被执行,而是直接执行
defer
然后再退出到上层
恢复
- 在
defer
中使用recover
函数用于异常恢复 panic
会在同一个goroutine
中的defer
调用中寻找到第一个recover
用于恢复,恢复了之后就没有panic
了,剩余业务函数也能继续执行recover
可以放在中间件中,防止业务崩溃
嵌套
panic
会遍历defer
链来寻找recover
,但是有可能在defer
中同样发生panic
然后就嵌套了- 先前发生的panic会被后面嵌套发生的panic覆盖,因此panic信息可以被输出,但是实际传入recover的panic只有最后发生的,也就是正在传递的panic
底层原理
¶panic
- 由于panic可能嵌套,因此运行时也会创建
_panic
结构体,然后放入协程的链表中,与defer一样 - panic简单遍历defer链表,对于栈分配或堆分配实现的defer语句,使用反射调用。因为直接调用需要再栈中为defer准备参数,而不同defer函数的参数大小差异很大,
gopanic
函数的栈帧大小固定且很小,装不下 - 对于内联汇编实现的defer,则在发生panic后调用
runtime.addOneOpenDeferFrame
扫描函数栈帧,如果发现有内联defer,则新建_defer
并插入到链表的指定位置
¶recover
- 本质就是将
_panic
中的recovered
字段设置为真,然后返回 gorecover
并没有真正处理异常,处理异常的是gopanic
本身。当发现panic被recover后,会删除当前链表中内联defer的结构体,恢复正常执行recover
通过修改协程SP、PC寄存器使函数重新执行deferreturn
函数,用于继续执行剩余的defer部分
【Go笔记】异常与异常捕获
https://study.0x535a.cn/go-note/go-panic-recover/