golang 源码分析之panic&recover

panic&recover
panic 能够改变程序的控制流,函数调用panic 时会立刻停止执行函数的其他代码,并在执行结束后在当前 Goroutine 中递归执行调用方的延迟函数调用 defer

recover 可以中止 panic 造成的程序崩溃。它是一个只能在 defer 中发挥作用的函数,在其他作用域中调用不会发挥任何作用

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

panic

//go:notinheap
type _panic struct {
	argp      unsafe.Pointer //指向 defer 调用时参数的指针
	arg       interface{}    // 参数
	link      *_panic        // 多个panic用链表连接
	pc        uintptr        // 如果忽略了此紧急情况,将在运行时返回哪里  记录pc
	sp        unsafe.Pointer // 如果忽略了此紧急情况,将在运行时返回哪里  记录sp
	recovered bool           // 是否已经被recover
	aborted   bool           // 是否被强行终止
	goexit    bool           // 是否runtime.goexit
}

遇到panic的处理步骤 runtime.gopanic

1 创建新的 runtime._panic 结构并添加到所在 Goroutine _panic 链表的最前面;
2 在循环中不断从当前 Goroutine 的 _defer 中链表获取 runtime._defer 并调用 runtime.reflectcall 运行延迟调用函数;
3 调用 runtime.fatalpanic 中止整个程序;

recover:runtime.gorecover

func gorecover(argp uintptr) interface{} {
	gp := getg()
	p := gp._panic
	if p != nil && !p.goexit && !p.recovered && argp == uintptr(p.argp) {
		// 恢复
		p.recovered = true
		// 返回参数
		return p.arg
	}
	return nil
}

小结

1、编译器会负责做转换关键字的工作;
    1.将 panic 和 recover 分别转换成 runtime.gopanic 和 runtime.gorecover;
    2.将 defer 转换成 deferproc 函数;
    3.在调用 defer 的函数末尾调用 deferreturn 函数;
2、在运行过程中遇到 gopanic 方法时,会从 Goroutine 的链表依次取出 _defer 结构体并执行;
3、如果调用延迟执行函数时遇到了 gorecover 就会将 _panic.recovered 标记成 true 并返回 panic 的参数;
    1.在这次调用结束之后,gopanic 会从 _defer 结构体中取出程序计数器 pc 和栈指针 sp 并调用 recovery 函数进行恢复程序;
    2.recovery 会根据传入的 pc 和 sp 跳转回 deferproc;
    3.编译器自动生成的代码会发现 deferproc 的返回值不为 0,这时会跳回 deferreturn 并恢复到正常的执行流程;
4、如果没有遇到 gorecover 就会依次遍历所有的 _defer 结构,并在最后调用 fatalpanic 中止程序、打印 panic 的参数并返回错误码 2;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值