Go语言defer学习笔记

本文详细解析了Go语言中的defer关键字,包括其工作原理、底层结构、执行过程、内存分配策略(栈上、堆上和内联分配),以及defer与return的关系,特别关注了内存逃逸对分配方式的影响。
摘要由CSDN通过智能技术生成

defer是什么

defer是Go语言的一个关键字,defer关键字后跟的函数或者方法能够延迟到执行return或panic时再进行调用。

defer的使用方法

defer func(aoth)

这样就能注册一个defer函数,使其在函数结束之前进行调用,参数和函数名都会固定。

defer的底层结构

当我们在使用defer函数的时候,编译器会生成一个_defer的结构体,一个函数中可能会存在多次的defer调用,多个_defer结构体之间是以链式存储的方式存储的,最终形成一个_defer的链表。而一个goroutine中的_defer字段就是指向_defer结构体的头节点。
在这里插入图片描述
这个过程中,每当创建一个defer结构体,就会从表头进行插入。当执行return函数时,又会从表头依次执行,FILO。

defer的执行过程

defer在执行过程中,会在底层插入两种函数:

  • defer内存分配函数:deferproc(堆内存分配)和deferprocStack(栈分配)
  • defer执行函数:deferreturn

defer相关的处理逻辑相关源码在cmd/compile/internal/ssagen/ssa.go文件中的state.stmt()方法中。

defer的内存分配

defer内存分配的过程主要有三种方式:

  • 内联分配
  • 栈上分配
  • 堆上分配

defer在分配内存的过程中分配的位置不一样,意为这分配时使用的函数也不相同。在栈上分配时使用deferprocStack函数,而堆上分配时使用deferproc函数。

在堆上分配

相应源码在src/runtime/panic.go文件中。
defer在堆上分配时,运用到了内存池的思想。首先会在逻辑处理器p本地和全局的defer缓存池中找到可用的_defer结构体,找不到之后才会在堆上新创建一个。(源码中newdefer()函数部分)比较常见的情况是在defer调用的函数有创建新对象或切片的操作。

栈上分配

栈上分配主要用的是deferprocStack()函数,go语言在编译过程中如果判断_defer需要在栈上分配,编译器会直接在函数调用栈上初始化_defer记录, 并作为参数传递给deferprocStack()函数。常见的情况是defer调用的函数涉及一些简单的操作如函数调用,修改局部变量。

内联分配

内联分配主要是go语言在编译阶段,会将一些确定的defer函数直接与代码块进行关联,直接在函数末尾对defer进行调用,减少函数调用的开销。

内联分配会进行defer是否在循环体内调用的判断,因为defer在循环体内调用,defer不确定循环体会调用几次,会存在逃逸到堆上的情况,这样会导致性能下降的问题。

从源码中总结如下:
一般情况下,go会优先使用内联的方式进行defer结构体的内存分配,但是需要满足一下几个条件:

  • build编译的时候没有设置-N
  • defer函数个数没有超过8个
  • defer所在函数返回值个数和defer函数个数乘积不超过15个
  • defer没有出现在循环语句中

内联分配相应源码在cmd/compile/internal/walk/stmt.go文件中的walkStmt()函数和cmd/compile/internal/ssagen/ssa.go的buildssa()函数中。

总的来说,会优先选择内联分配的方式进行内存分配。当内联分配不满足,且没有发生内存逃逸时会选择栈上分配的方式。当发生内存逃逸,则使用堆上分配的方式。

defer能修改返回值么,defer与return的关系是怎么样的?

defer能返回修改值,当defer调用的函数有显示返回值的时候,是可以修改返回值的。
return的过程一般是这样:计算返回值(如果有的话),执行defer语句,进行实际的返回,所以defer语句会在return前执行。如果defer调用的函数存在显示返回值时,会对return的返回值造成影响。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值