欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

defer原理、性能、优化

程序员文章站 2022-04-16 08:15:36
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
 }