从GO内存模型与调用协议理解defer closure的坑
资料参考:
- 官网defer介绍: https://blog.golang.org/defer-panic-and-recover
- 深入解析go:
问题点
- 非命名返回值
package main
import "fmt"
func Test() (int) {
ret := 123
defer func() {
fmt.Println("first defer:",ret)
}()
defer func() {
ret++
fmt.Println("Inner:", ret)
}()
return ret
}
func main() {
fmt.Println(Test())
}
打印结果是123
- 命名返回值
package main
import "fmt"
func Test() (ret int) {
ret = 123
defer func() {
fmt.Println("first defer:",ret)
}()
defer func() {
ret++
fmt.Println("Inner:", ret)
}()
return ret
}
func main() {
fmt.Println(Test())
}
打印结果是124
前者123, 后者124? 怎么理解!
关键点
Go的return语句不是原子指令! 底层被分解为:
1. 返回值=xxx
2. 调用defer函数
3. 空的return
其实这种理解也是错的!
根据Go的内存模型及调用协议:
- GO在调用栈(Stack)的方法帧(frame)里, 在参数(arguments)之上保留返回值(returnValue)的位置.
方法帧(frame):
返回值0
返回值1
...
实参0
实参1
...
- return语句设置返回值. 如果是命名返回值, 则可在defer closure中引用.
- 执行defer函数栈.
从这个层面理解, return语句也是原子指令.
通俗说
- 根据Go的内存模型与调用协议知道, 函数帧会保留前N个位置用于保存返回值. 如果返回值是命名的, 则这几个位置可以直接访问.
- return语句将值设置到返回值的保留位置. 原则上说return语句也是原子指令.
- defer栈return语句或函数结束后调用. 如果操作了返回值(命名返回值), 其值是可见的!
需要明确的是, 非命名返回值一般不受影响.
但也可以看出, 命名返回值某种程度节省了赋值指令.
从GO内存模型与调用协议理解defer closure的坑的更多相关文章
- 对Java内存模型即JMM的理解
类似物理上的计算机系统,Java虚拟机规范中也定义了一种Java内存模型,即Java Memory Model(JMM),来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能 ...
- Java内存模型解惑--观深入理解Java内存模型系列文章有感(二)
1.volatile关键字修饰的域的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用 ...
- Java内存模型原理,你真的理解吗?
[51CTO.com原创稿件]这篇文章主要介绍模型产生的问题背景,解决的问题,处理思路,相关实现规则,环环相扣,希望读者看完这篇文章后能对 Java 内存模型体系产生一个相对清晰的理解,知其然知其所以 ...
- 《深入理解Java虚拟机》-----第12章 Java内存模型与线程
概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能了.在许多情况下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统速 ...
- 深入理解Java虚拟机内存模型
前言 本文中部分内容引用至<深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)>第12章,如果有兴趣可自行深入阅读,文末放有书籍PDF版本连接. 一.物理机中的并发 物理机遇到的并 ...
- 全面理解Java内存模型(JMM)及volatile关键字(转载)
关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...
- 全面理解Java内存模型(JMM)及volatile关键字(转)
原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型( ...
- 如何从编程的本质理解JVM内存模型
如何从编程的本质理解JVM内存模型 一般聊JVM内存模型都是把图截出来,然后对着图,解释上面堆.栈之类的概念.这篇将分享下,如何从编程的本质上理解,JVM内存模型是什么样子,为什么是这个样子,不再死记 ...
- Java的内存模型
"让计算机并发执行若干个运算任务"与"更充分地利用计算机处理器的效能"之间的因果关系,看起来顺理成章,实际上它们之间的关系并没有想象中的那么简单,其中一个重要的 ...
随机推荐
- [H5]range对象的setStart/setEnd方法
1.setStart:表示某个节点的range对象的起点位置;2.setEnd:表示某个节点的range对象的结束位置; 示例如下:<body> <div id="div& ...
- Java中几种常量池的区分
转载自:https://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/ 在java的内存分配中,经常听到很多关于常量 ...
- 这可能是新手最容易入门的JVM讲解(不过是一场恋爱)
作者:请叫我红领巾,转载请注明出处http://www.cnblogs.com/xxzhuang/p/7453746.html 一.写在前面 首先,本篇文章并没有涉及原理,而是在笔者撸了<深入理 ...
- linux(九)之网络基础
一.ping命令 1.1.作用 用于检测主机.执行ping指令会使用ICMP传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,因而得知该主机运作正常. 1.2.命令说明 pi ...
- hdu5673 Robot 卡特兰数 / 默慈金数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5673 分析: 这道题是一道裸的默慈金数,比较容易想到的是用卡特兰数来做.不了解的可以先学习一下. 卡特 ...
- Windows 8 快捷键
三月份,Kurt Walter 在 Windows团队博客中发表了一篇介绍 Windows 8 和全新快捷键的精彩文章. Windows 8 提供了出色的触摸体验,但在我的台式机上使用了几个月后我还发 ...
- Java基础---继承、抽象、接口
一.概述 继承是面向对象的一个重要特征.当多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继那个类即可.这时,多个类可以称为子类,单 ...
- SQL Server内存
背景 最近一个客户找到我说是所有的SQL Server 服务器的内存都被用光了,然后截图给我看了一台服务器的任务管理器.如图 这里要说明一下任务管理器不会完整的告诉真的内存或者CPU的使用情况,也就是 ...
- spring mvc:事务引起的try/catch失效
在测试一个接口时,发现一个奇怪的现象:该接口使用@ResponseBody注解返回json格式数据,并且使用try/catch包括全部逻辑代码,debug后发现返回数据没有任何错误,只包含一段因产生异 ...
- C#格式符
在输出字符串时,使用格式说明 使字符串显示适当的格式,比如:货币格式,或者科学计数法.百分比等. 以下是格式化的数字字符串 格式. {index, alignment: format} 例如: ; ...