2020-11-19:go中,defer原理是什么?

举报
福大大架构师每日一题 发表于 2020/11/19 22:27:41 2020/11/19
3.1k+ 0 0
【摘要】 福哥答案2020-11-19:- - 什么是defer - defer是go语言提供的一种用于注册延迟调用的机制:让函数或者语句在当前函数执行完毕(包括return正常结束或者panic导致的异常结束)之后执行。 - defer语句通常用于一些成对的操作场景,打开/关闭连接,加锁/解锁,打开文件/关闭文件等等 - defer在一些需要回收资源的场景中非常有用 - 为什么需...

福哥答案2020-11-19:

- - 什么是defer

    - defer是go语言提供的一种用于注册延迟调用的机制:让函数或者语句在当前函数执行完毕(包括return正常结束或者panic导致的异常结束)之后执行。

    - defer语句通常用于一些成对的操作场景,打开/关闭连接,加锁/解锁,打开文件/关闭文件等等

    - defer在一些需要回收资源的场景中非常有用

  - 为什么需要defer

    - 有效防止内存泄漏

  - defer底层原理 

    - 每次defer语句在执行的时候,都会将函数进行“压栈”,函数参数会被拷贝下来。当外层函数退出时,defer函数会按照定义的顺序逆序执行。如果defer执行的函数为nil,那么会在最终调用函数中产生panic。

    - 编译器会把 defer 语句翻译成对 deferproc 函数的调用,同时,编译器也会在使用了 defer 语句的 go 函数的末尾插入对 deferreturn 函数的调用。

    - 每一个goroutine结构体中都有一个_defer 指针变量用来存放defer单链表。defer保存用什么数据结构?回答栈过不了面试官那关,defer单链表应该能过关。_defer 结构体如下:

        - siz:所有传入参数的总大小。

        - started:该 defer 是否已经执行过。

        - heap:表明该defer是否存储在heap上。

        - sp:函数栈指针寄存器,一般指向当前函数栈的栈顶。

        - pc:程序计数器,有时称为指令指针(IP),线程利用它来跟踪下一个要执行的指令。在大多数处理器中,PC指向的是下一条指令,而不是当前指令。

        - fn:指向传入的函数地址和参数。

        - _panic:指向 _panic 链表。

        - link:指向 _defer 链表。

    - 为什么defer要按照定义的顺序逆序执行:后面定义的函数可能会依赖前面的资源,所以要先执行。如果前面先执行,释放掉这个依赖,那后面的函数就不能找到它的依赖了。

    - defer函数定义时,对外部变量的引用方式有两种,分别是函数参数以及作为闭包引用。在作为函数参数的时候,在defer定义时就把值传递给defer,并被cache起来。如果是作为闭包引用,则会在defer真正调用的时候,根据整个上下文云确定当前的值。

    - defer后面的语句在执行的时候,函数调用的参数会被保存起来,也就是复制一份。在真正执行的时候,实际上用到的是复制的变量,也就是说,如果这个变量是一个“值类型”,那他就和定义的时候是一致的,如果是一个“引用”,那么就可能和定义的时候的值不一致

  - 利用defer原理

    - 利用defer先求值,再延迟调用的性质

  - defer与return

  - defer语句的参数

    - defer语句表达式的值在定义的时候就已经确定了

  - 闭包:由函数以及相关引用环境组合而成的实例,也就是说闭包=函数+引用环境

  - 匿名函数:匿名函数就是我们说的闭包,它不能独立存在,但可以直接调用或者赋值于某个变量。一个闭包,继承了函数声明时的作用域。在go语言中,所有的匿名函数都是闭包

- defer配合recover

  - recover:异常捕获,可以让程序在引发panic的时候不会崩溃退出。在引发panic的时候,panic会停掉当前正在执行的程序,但是,在这之前,它会有序的执行完当前goroutine的defer列表的语句。所以我们通常在defer里面挂一个recover,防止程序直接挂掉,类似于try...catch.recover()函数只在defer的上下文中才有效,直接调用,会返回nil

***

[评论,有好几个参考地址](https://user.qzone.qq.com/3182319461/blog/1605740826)

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。