defer原理、性能、优化
程序员文章站
2022-07-06 12:32:08
1、defer执行时机 go //defer初始化值和位置有关 推迟执行的仅仅是函数体 func f3(j int) (i int) { defer func(a int) { i += a log.Println(" ",j) //退出阶段j=100 进入阶段j=10 a=10 }(j) j =1 ......
1、defer执行时机
for i:=1;i<10;i++{ defer log.println(i) }
上面那段简单的代码基本就可以说明多个defer时的执行顺序了
当代码中出现defer时,会将defer要执行的函数压人栈,然后等函数执行完毕再执行defer栈中的内容
go1.13以前用堆分配,加入到链表中,再尾递归调用,go1.13在栈上分配,如果defer过多则还是会在堆上用链表来管理
go1.14则做了进一步优化,defer的开销基本很小了。
2、defer的估值时刻
defer的赋值操作并不是延迟赋值的,还是按照语句顺序赋值的
如下:
//defer初始化值和位置有关 推迟执行的仅仅是函数体 func f3(j int) (i int) { defer func(a int) { i += a log.println("------------",j) //退出阶段j=100 进入阶段j=10 a=10 }(j) j =100 //defer初始化值和位置有关 return }
如果我们如下调用
f3(10)
则a的值为10,而打印的j最后会被打印100
defer分为进入阶段和退出阶段
在看下面的例子
func f4(j int) (i int) { j =100 //defer初始化值和位置有关 defer func(a int) { i += a }(j) return }
a=100
3、防止defer内存泄漏
下面这段代码会严重占用内存栈,造成短暂内存泄漏,有大量的文件句柄没有被释放
//内存泄漏 func writemanyfiles(files []os.file) error { for _, file := range files { defer file.close() } return nil }
用函数包裹之后每循环一个就关闭一个文件句柄
//防止内存泄漏 func writemanyfiles(files []os.file) error { for _, file := range files { if err:= func() error { f, err := os.open(file) defer f.close() if err != nil { return err }else { return nil } }();err!=nil{ return err } } return nil }
上一篇: docker常用命令