defer
defer执行顺序
- defer挂接在G结构体下,多个defer形成链表,defer结构体如下
type _defer struct {
heap bool
rangefunc bool // true for rangefunc list
sp uintptr // sp at time of defer
pc uintptr // pc at time of defer
fn func () // can be nil for open-coded defers
link *_defer // next defer on G; can point to either heap or stack!
// If rangefunc is true, *head is the head of the atomic linked list
// during a range-over-func execution.
head *atomic.Pointer[_defer]
}
- defer语句调用deferporc函数,new一个_defer结构体,挂到g上,ret指令前,调用deferreturn函数完成_defer 链表的遍历,执行完链表的所有defer函数,每执行完一个defer函数,会将当前_defer结构体从链表里移除,
- 判断sp是否是调用者SP,如果不是则直接返回,通过jumpdefer函数跳转到函数去执行。
- defer演变: 堆上分配-栈上分配-open code defer(通过一个字节标记8个defer是否执行)
- deferproc函数
func deferproc(fn func()) {
gp := getg()
if gp.m.curg != gp {
// go code on the system stack can't defer
throw("defer on system stack")
}
d := newdefer()
d.link = gp._defer
gp._defer = d
d.fn = fn
d.pc = getcallerpc()
// We must not be preempted between calling getcallersp and
// storing it to d.sp because getcallersp's result is a
// uintptr stack pointer.
d.sp = getcallersp()
// deferproc returns 0 normally.
// a deferred func that stops a panic
// makes the deferproc return 1.
// the code the compiler generates always
// checks the return value and jumps to the
// end of the function if deferproc returns != 0.
return0()
// No code can go here - the C return register has
// been set and must not be clobbered.
}
- deferreturn函数
func deferreturn() {
var p _panic
p.deferreturn = true
p.start(getcallerpc(), unsafe.Pointer(getcallersp()))
for {
fn, ok := p.nextDefer()
if !ok {
break
}
fn()
}
}