// Create a new deferred function fn, which has no arguments and results.
// The compiler turns a defer statement into a call to this.
func deferproc(fn func()) {
// 获取当前的G
gp := getg()
if gp.m.curg != gp {
// go code on the system stack can't defer
throw("defer on system stack")
}
d := newdefer()
if d._panic != nil {
throw("deferproc: d.panic != nil after newdefer")
}
// 链表结构,将d插入到表头。先入后出
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 runs deferred functions for the caller's frame.
// The compiler inserts a call to this at the end of any
// function which calls defer.
func deferreturn() {
gp := getg()
for {
d := gp._defer
if d == nil {
return
}
sp := getcallersp()
// 链表保存了所有闭包,需要判断sp以防止调用到其它函数的defer方法
if d.sp != sp {
return
}
if d.openDefer {
done := runOpenDeferFrame(d)
if !done {
throw("unfinished open-coded defers in deferreturn")
}
gp._defer = d.link
freedefer(d)
// If this frame uses open defers, then this
// must be the only defer record for the
// frame, so we can just return.
return
}
fn := d.fn
d.fn = nil
gp._defer = d.link
freedefer(d)
fn()
}
}
defer是如何实现的,我们用通过汇编来看看
打印汇编
go build -gcflags="-S" main.go
原来defer的语句是一个函数,在函数退出时调用它。
如果defer的个数不是静态的,怎么调用?
再看看main函数的汇编
这次循环把defer后面的函数放到runtime.deferproc(SB)中,然后在函数结尾调用runtime.deferreturn(SB)。
当defer较多时,最终还是用链表来实现的