当前位置: 首页 > news >正文

golang panic原理

数据结构与底层实现

Goroutine结构体

stack(栈内存范围)
结构体类型,包含 lo(低地址)和 hi(高地址)两个 uintptr 字段,描述 Goroutine 的栈内存区间 [lo, hi)。初始栈大小为 2KB,可动态扩容至 1GB。

m(Machine 绑定)
指向当前运行此 Goroutine 的内核线程(M)。调度器通过 M 将 Goroutine 映射到操作系统线程。

_panic 和 _defer(异常与延迟调用链)

  • _panic:指向当前最内层的 panic 结构体链表,处理异常传播。
  • _defer:指向延迟调用(defer)链表,按后进先出(LIFO)顺序执行清理操作。
type g struct {
	// Stack parameters.
	// stack describes the actual stack memory: [stack.lo, stack.hi).
	// stackguard0 is the stack pointer compared in the Go stack growth prologue.
	// It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
	// stackguard1 is the stack pointer compared in the //go:systemstack stack growth prologue.
	// It is stack.lo+StackGuard on g0 and gsignal stacks.
	// It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
	stack       stack   // offset known to runtime/cgo
	stackguard0 uintptr // offset known to liblink
	stackguard1 uintptr // offset known to liblink

	_panic    *_panic // innermost panic - offset known to liblink
	_defer    *_defer // innermost defer
	m         *m      // current m; offset known to arm liblink
	sched     gobuf
    
    ......
}

panic结构体

从上述Goroutine结构体的定义,我们可以发现每一个Goroutine维护一个panic的链表,panic存储在栈上。

// _panic 保存了一个活跃的 panic 信息。

// _panic 的值必须仅存在于栈上。

// argp 和 link 字段是栈指针,但在栈增长时无需特殊处理:
// 由于它们是指针类型且 _panic 值仅存在于栈上,
// 常规的栈指针调整机制会自动处理这些字段。
type _panic struct {
	argp unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink
	arg  any            // argument to panic
	link *_panic        // link to earlier panic

	// startPC and startSP track where _panic.start was called.
	startPC uintptr
	startSP unsafe.Pointer

	// The current stack frame that we're running deferred calls for.
	sp unsafe.Pointer
	lr uintptr
	fp unsafe.Pointer

	// retpc stores the PC where the panic should jump back to, if the
	// function last returned by _panic.next() recovers the panic.
	retpc uintptr

	// Extra state for handling open-coded defers.
	deferBitsPtr *uint8
	slotsPtr     unsafe.Pointer

	recovered   bool // whether this panic has been recovered
	goexit      bool
	deferreturn bool
}

注意事项

golang中每个goroutine维护自己的panic信息,并不是全局的,所以,如果需要捕获panic信息需要在每个goroutine中处理。

所以,在下面的这个案例中recover不能捕获到panic信息。如果需要捕获到,需要在每个协程中都执行recover的逻辑。

func main() {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Recovered from panic: %v", r)
			os.Exit(1)
		}
	}()
	// 业务代码...
	go func() {
		testPanic()
	}()
	time.Sleep(1 * time.Second)
}

相关文章:

  • 解锁大数据治理:开启数据驱动的新时代
  • 图片粘贴上传实现
  • python统计项目计划中2个日期之间的工作天数
  • ubuntu上/etc/profile.d/目录的作用
  • 保护大数据的最佳实践方案
  • 深入理解TypeScript中的类型守卫
  • C# 中的 lock用法
  • Spring Bean 生命周期的执行流程
  • ES12 weakRefs的用法和使用场景
  • frameworks 之 Activity添加View
  • Canal 部署binlog 监听
  • 【MySQL】环境变量配置
  • Linux 命令
  • 汽车长期不保养的危害
  • 【鸿蒙Next】鸿蒙应用发布前的准备
  • 泰山派RK3566移植QT,动鼠标时出现屏幕闪烁
  • 微信支付V3平台证书切换成公钥遇到的问题。【无可用的平台证书,请在商户平台-API安全申请使用微信支付公钥】【 Illegal base64 character 2d】
  • 【CCF CSP-J 2023】一元二次方程
  • U-Net 与深度学习的完美结合:图像分割的高效解决方案
  • Windows 环境下配置多个不同版本的 Maven
  • 《水饺皇后》领跑五一档票房,《哪吒2》上座率仍居第一
  • 美国第一季度经济环比萎缩0.3%,特朗普:怪拜登,与关税无关
  • 王受文已任中华全国工商业联合会领导班子成员
  • “五一”逃离城市计划:带上帐篷去大自然里充电
  • 圆桌|如何应对特朗普政府的关税霸凌?一种联合国视角的思考
  • 五一“拼假”催热超长假期,热门酒店民宿一房难求