从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的内存模型
"让计算机并发执行若干个运算任务"与"更充分地利用计算机处理器的效能"之间的因果关系,看起来顺理成章,实际上它们之间的关系并没有想象中的那么简单,其中一个重要的 ...
随机推荐
- NetBeans主题配色方案加设置.md
1.网上下载主题的地址是:http://netbeansthemes.com/ **上面的主题我看了下但是感觉不太适合自己所以自己就仿照的设置了下下面我附上自己的配置信息 感兴趣的可以下载下来自己看下 ...
- java api1.8中文版(由谷歌,百度,有道,必应翻译).md
大家如果想看java1.8 的中文api可以点击我下面提供的链接,同时感谢把这些资源放到网上供我们学习的朋友,废话不说了下面就是链接: java 1.6 帮助文档 中文 链接:http://downl ...
- SLF4J源码解析-LoggerFactory(二)
承接前文SLF4J源码解析-LoggerFactory(一),本文则主要针对获取ILoggerFactory对象作下简单的分析 LoggerFactory#getILoggerFactory() 源码 ...
- Python第一天---第一个Python程序
1.我的环境是windows下,需要安装notepad++,安装Python2,配置环境变量(百度下可以见) 2.打开cmd窗口-----输入I: [输入要在哪个磁盘存储python代码(我的在I: ...
- Windbg调试关键区(CriticalSection)死锁
一. 准备工作 这里一个有关键区锁死问题的程序,运行之后依次点击"CS锁死"按钮.右上角退出按钮,程序就会卡死.(图1) 对于眼下的这个问题,界面完全失去响应,这说明负责消息处理的 ...
- 7.28.1 Spring构造注入还是设置注入
1. 构造方法注入代码如下:public UserManagerImpl(UserDao userDao) { ...
- 为shell布置陷阱:trap捕捉信号方法论
本文目录: 1.1 信号说明 1.2 trap布置陷阱 1.3 布置完美陷阱必备知识 家里有老鼠,快消灭它!哎,又给跑了.老鼠这小东西跑那么快,想直接直接消灭它还真不那么容易.于是,老鼠药.老鼠夹子或 ...
- 如何利用Jmeter做代理录制脚本
如果对于这个Jmeter不太会使用的童鞋,可以去参考其他的教学文档,本文只提供Jmeter的代理使用. 第一步:添加线程组
- DB Error || Warning
数据库在进行增删改查时有时候会发生错误,当在程序中一个操作总是不起作用的时候,我们可以尝试如下方法: 1.输出sql语句,有的sql语句可能是通过一些字符拼接完成的,这时候可能会发生'', +之类的混 ...
- SSH2项目网上书店系统手把手教学_Struts2+Spring+Hibernate整合开发
一 序言 鉴于目前J2EE的火热程度,SSH2是每个学生毕业前都必须掌握的一门技术,所以在这里我就使用SSH2技术做一个小型项目,和大家一起学习. SSH2技术的基础概论就不再提了,直接说特点吧. 1 ...