前面几章内容
(一) go协程栈底层讲解
(二) go的堆内存结构分析
(三) 高级语言垃圾回收思路和如何减少性能影响原理分析
本节主要分为三节讲解栈内存(go中的协程栈、调用栈)、堆内存、go中的垃圾回收底层相关知识
这几节知识和go语言在高并发特性息息相关,所以很值得分析分析,同时也能大佬们在设计程序语言时的思想
我们之前学习go的协程栈时,有一个程序内部的示意图,也就是下面这个样子。整体区域就是go中的栈区(RAM stack),里面是放go的栈内存的,中间的小块是放go一个协程的协程栈,我们之前学到,一个协程栈的第一个方法是goexit() ,它是为了退出之后重新进行调度用户方法的,后面的就是用户的一个一个方法了。

协程除了上面能记录协程执行的路径,另外还能存储一些信息,比如局部变量、函数传参、函数的返回值。这些都与c/c++ 类似。
小结一下:go 协程栈的作用
有这么一段代码, 我们来分析一下里面的协程栈结构


2. 通过runtime.main 进入用户的main,这里的main.main 需要开多大,是由编译器分析的

3. 填入程序的参数,其中函数参数进入栈帧是最后一个参数开始的

4. 程序执行的过程步骤

从上面的例子分析
由于每个协程栈是紧挨着的(下面示意图),那么问题来了

协程栈不够大怎么办? 如果当中有一个协程栈不够大,但是下面有其他的协程栈,这时应该怎么办?
通过资料发现,这些情况能导致协程栈大
紧接着上一节的思考,学习这一章节
在go 中协程栈只有2k-4k, 不能和线程的栈大小比(线程用兆M为单位计算的)
下面通过两个主要原因进行分析学习
局部变量太大往往会出现逃逸现象,我们针对逃逸现象进行分析
什么是逃逸分析呢?
简单来说: 变量是由栈上-----> 堆上(在java语言中貌似也有)
不是所有的变量都能放在协程栈上(下面是里两个原因)
在逃逸分析,我们需要分析下面三个具体的原因:
指的是: 本应该是局部变量的,但是返回给了返回值,这时就放在了堆上
术语描述: 函数的返回了对象的指针

下面是一个简单的打印代码:,但我们看下println的函数接口,

它里面是一个空接口,所以可能会逃逸

分析:
在方法中如果出现栈帧太多的情况,程序内部会采用栈扩容方法进行处理
栈扩容
分段栈的情况是: 假如第一个栈帧空间不够,直接使用图中箭头指向的空间
可以想象一下,当一个栈里面出现大量栈帧空间不够用时,使用这种方法会在不连续的空间来回跳转
优点: 没有空间浪费
缺点: 栈指针会再不连续的空间跳转(当两块空间中有返回值时)

连续栈: 直接将原先栈空间不够的拷贝到新开辟的栈空间
优点: 空间一直连续
缺点: 伸缩时的开销大
原理: 当空间不足时扩容,变为原来的2倍;当空间使用率不足1/4时缩容,变为原来的1/2。
连续栈的示意图:

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习