【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/
Author
Stephen Zeng
Posted on
August 21, 2025
Licensed under