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()
    }
}

results matching ""

    No results matching ""