GopherCon SG 2019 "Understanding Allocations" 学习笔记
本篇是根据 GopherCon SG 2019 “Understanding Allocations” 演讲的学习笔记。
Understanding Allocations: the Stack and the Heap - GopherCon SG 2019 - YouTube
理解分配:栈和堆

你的程序中有两种内存,栈内存和堆内存。
go 中,每个 go 程都会有一个栈空间,整个程序有一个堆空间。
变量是在栈还是堆上

负责堆垃圾回收的 GC 会导致整个程序的延迟,而不仅仅是创建垃圾的部分。你可能会担心你的代码在堆中产生了多少垃圾。
什么时候需要优化

要有 benchmarks 基准来证明你的程序不够快(有大量的堆内存分配),够快就不用多此一举了。
你要先确保程序能正确运作(业务处理),而不是先着重性能优化。
在有大量指针+运行快速的程序、清晰明了+但有点慢的程序之间,你应该选择后者。
普通类型参数传递
第5行进入squre函数

函数和局部变量被挤压入栈,一个函数为一个堆栈帧。
squre函数执行完

执行完成后,你会发现黑线(只是用于区分)向上移,上方内容为有效内容,下方内容为无效内容(过期而不再使用)
第6行执行println函数

go 声明了新的内存部分,我们有了新的堆栈帧用于打印行,黑线下移。
通俗的来讲,栈空间会进行自我清理,任何变量都会被清理干净,空间会被重复使用。
指针类型参数传递
第4行声明变量

main 函数和变量 n 被压入栈。
第5行进入inc函数

inc 函数和变量 x 被压入栈,属于另一个堆栈帧,黑线下移。传入的变量是 n 的地址。
inc函数执行完

黑线上移,n 被修改了值。并没有什么问题。
执行println函数

总结
虽然使用了指针传参,但这种情况下它能够留在栈上,即共享向下传递时,通常留在栈空间上。(主函数将自己的变量传给子函数)
函数返回引用
第4行进入answer函数前

编译器推断出 n 是 int 的指针类型,赋初值 nil 等待函数返回结果。
进入函数

在函数内部声明了变量并初始化,并返回了变量的内存地址。
执行println函数

致命的问题
你会发现,我明明没有进行赋值修改的操作,但却破坏了原有的值。原因在于
- 调用
answer函数的时候,假如我们把声明的变量x放在栈空间,返回变量的地址。 - 那么
main函数中的n会拿到x的地址,当answer方法退出时(黑线上移),该堆栈帧已过期,但是n还引用着x。 - 我们知道堆栈的空间是可以被重复利用的,那么下一次执行其他函数或者声明变量的时候,那块过期的内存区域就会被重新使用,修改为其他值。
- 案例中调用
println,黑线下移,产生新的堆栈帧,原先x标识符被替换成了a,修改a的值等同修改了n地址解引用后的值。这是非常致命的错误。
解决的方法

为了解决上述致命的问题,被声明初始化的 x 变量就需要“逃逸”到堆空间中。这样其他无关函数就不会对它的值产生影响。
共享向上传递时,通常留在堆空间上。(子函数将自己的变量传给主函数,引用)
Escape Analysis
编译器怎么判断的


变量只在函数里工作,那就分配到栈空间上。如果编译器不能证明函数返回后声明过的变量是否被引用,那必须将其分配到堆空间上。
询问编译器

查看构建指令,可以提供一个 -gcflags 的可选参数,传递给 go tool compile 工具

查询 go tool compile -h,得知参数 -m 可以输出编译器的优化决定(变量放在栈还是堆上)

执行 go build -gcflags "-m" 获取到下面的结果


总结


什么时候会把变量分配在堆内存上
- 函数返回退出后声明过的变量依旧被引用着。
- 变量初始化值大小过大无法分配进栈。
- 不知道变量值的具体大小,比如切片。
做个判断

看看前面总结的第一点和第三点。明显可以知道右边那个是分配在栈上,而左边那个分配在堆上。
思考io.Reader接口

io 标准库里有个 Reader 接口,你应该知道为什么官方要用前者替换后者了吧。如果使用后者,会在堆上产生大量的垃圾,造成程序迟钝。前者则符合向下传递思想,变量通常分配在栈空间上。
最后

不要猜想,多用工具!
GopherCon SG 2019 "Understanding Allocations" 学习笔记的更多相关文章
- 2019暑假Java学习笔记(二)
目录 基础语法(下) 流程控制 if语句 switch语句 while语句和do-while语句 for语句 break关键字 continue关键字 数组 一维数组 二维数组 用户输入操作 练习题: ...
- 2019暑假Java学习笔记(一)
目录 基础语法(上) HelloWorld 变量 常量 数据类型 整数 浮点数 char类型 boolean类型 String 计算字符串长度 字符串比较 字符串连接 charAt()方法 字符串常用 ...
- 2019暑假Java学习笔记(三)
目录 面向对象 对象 构造方法 引用与对象实例 static final 封装 this 继承 super 方法重载与重写 多态 抽象类 接口 内部类 成员内部类 静态内部类 局部内部类 匿名内部类 ...
- Tensorflow学习笔记2019.01.22
tensorflow学习笔记2 edit by Strangewx 2019.01.04 4.1 机器学习基础 4.1.1 一般结构: 初始化模型参数:通常随机赋值,简单模型赋值0 训练数据:一般打乱 ...
- Tensorflow学习笔记2019.01.03
tensorflow学习笔记: 3.2 Tensorflow中定义数据流图 张量知识矩阵的一个超集. 超集:如果一个集合S2中的每一个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S ...
- AngularJs学习笔记--Understanding the Model Component
原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular文档讨论的上下文中,术语“model”可以 ...
- AngularJs学习笔记--Understanding the Controller Component
原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular中,controller是一个javasc ...
- AngularJs学习笔记--Understanding Angular Templates
原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model angular template是一个声明规范,与mode ...
- 2019国家集训队论文《整点计数》命题报告 学习笔记/Min25
\(2019\)国家集训队论文<整点计数>命题报告 学习笔记/\(Min25\) 补了个大坑 看了看提交记录,发现\(hz\)的\(xdm\)早过了... 前置知识,\(HAOI\)< ...
随机推荐
- 火狐firebug&firepath插件安装
火狐浏览器下掉了firebug和firepath插件,用户即使下载了火狐55以下的版本,也无法查找到这两个插件,以下方法可以解决哦 第1步:下载火狐55以内版本安装包,安装时迅速设置禁止自动更新版本, ...
- ARM中断与架构知识 精简知识点
目录 一.ARM系统的异常与中断 二.CPU模式与寄存器 1.ARM CPU模式 2.ARM CPU state,两种指令集 3.ARM CPU寄存器: 引申介绍一下存储空间中的数据存放 4.ARM三 ...
- chili
靶机准备 首先将靶机ova文件导入 网络模式改为NAT 扫描ip netdiscover -r 192.168.164.0/24 kali:192.168.164.137 渗透测试 扫描端口 nmap ...
- uoj310. 【UNR #2】黎明前的巧克力
题目描述: uoj 题解: WTF. 看题解看了一个小时才看明白. 首先有状态$f[i][j]$表示前$i$个东西两人取,最后两人异或和为$j$的有多少方案. 转移为$f[i][j]=f[i-1][j ...
- 知识点简单总结——FWT(快速沃尔什变换),FST(快速子集变换)
知识点简单总结--FWT(快速沃尔什变换),FST(快速子集变换) 闲话 博客园的markdown也太傻逼了吧. 快速沃尔什变换 位运算卷积 形如 $ f[ i ] = \sum\limits_{ j ...
- 【仿真】Carla之收集数据快速教程 (附完整代码) [7]
收集过程可视化展示,随后进入正文: 参考与前言 看到仿真群对这类任务下(用carla收集数据然后再做训练等) 需求量大,顺手马上写一个好了,首先收集数据需要考虑清楚: 收集什么数据,需要什么样的数据格 ...
- Apache Ranger安装部署
1.概述 Apache Ranger提供了一个集中式的安全管理框架,用户可以通过操作Ranger Admin页面来配置各种策略,从而实现对Hadoop生成组件,比如HDFS.YARN.Hive.HBa ...
- java-Map集合hei
/* Map集合的特点: Map集合市一个双列集合,一个元素包含两个值:一个key,一个value Map集合中的元素,key和value的数据类型可以相同,也可以不同 Map集合中的元素,key不允 ...
- Zookeeper 的典型应用场景 ?
Zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架,开发人员 可以使用它来进行分布式数据的发布和订阅. 通过对 Zookeeper 中丰富的数据节点进行交叉使用,配合 Watch ...
- 学习DNS(一)
DNS(Domain Name System,域名系统)因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户方便的访问互联网,而不用去记住能够被机器读取的IP数串.通过主机名,最终得到该主 ...