golangpanic原理
- 电脑硬件
- 2025-08-26 12:09:02

数据结构与底层实现 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) }golangpanic原理由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“golangpanic原理”