所在的位置: C++ >> C++介绍 >> golang2021数据格式88Go

golang2021数据格式88Go

在讨论变量生命周期之前,先来了解下计算机组成里两个非常重要的概念:堆和栈。

什么是栈

栈(Stack)是一种拥有特殊规则的线性表数据结构。

1)概念

栈只允许从线性表的同一端放入和取出数据,按照后进先出(LIFO,LastInFirstOut)的顺序,如下图所示。

图:栈的操作及扩展

往栈中放入元素的过程叫做入栈。入栈会增加栈的元素数量,最后放入的元素总是位于栈的顶部,最先放入的元素总是位于栈的底部。

从栈中取出元素时,只能从栈顶部取出。取出元素后,栈的元素数量会变少。最先放入的元素总是最后被取出,最后放入的元素总是最先被取出。不允许从栈底获取数据,也不允许对栈成员(除了栈顶部的成员)进行任何查看和修改操作。

栈的原理类似于将书籍一本一本地堆起来。书按顺序一本一本从顶部放入,要取书时只能从顶部一本一本取出。

2)变量和栈有什么关系

栈可用于内存分配,栈的分配和回收速度非常快。下面的代码展示了栈在内存分配上的作用:

funccalc(a,bint)int{varcintc=a*b

varxintx=c*10

returnx}

代码说明如下:

第1行,传入a、b两个整型参数。

第2行,声明整型变量c,运行时,c会分配一段内存用以存储c的数值。

第3行,将a和b相乘后赋值给c。

第5行,声明整型变量x,x也会被分配一段内存。

第6行,让c乘以10后赋值给变量x。

第8行,返回x的值。

上面的代码在没有任何优化的情况下,会进行变量c和x的分配过程。Go语言默认情况下会将c和x分配在栈上,这两个变量在calc()函数退出时就不再使用,函数结束时,保存c和x的栈内存再出栈释放内存,整个分配内存的过程通过栈的分配和回收都会非常迅速。

什么是堆

堆在内存分配中类似于往一个房间里摆放各种家具,家具的尺寸有大有小,分配内存时,需要找一块足够装下家具的空间再摆放家具。经过反复摆放和腾空家具后,房间里的空间会变得乱七八糟,此时再往这个空间里摆放家具会发现虽然有足够的空间,但各个空间分布在不同的区域,没有一段连续的空间来摆放家具。此时,内存分配器就需要对这些空间进行调整优化,如下图所示。

图:堆的分配及空间

堆分配内存和栈分配内存相比,堆适合不可预知大小的内存分配。但是为此付出的代价是分配速度较慢,而且会形成内存碎片。

变量逃逸(EscapeAnalysis)——自动决定变量分配方式,提高运行效率

堆和栈各有优缺点,该怎么在编程中处理这个问题呢?在C/C++语言中,需要开发者自己学习如何进行内存分配,选用怎样的内存分配方式来适应不同的算法需求。比如,函数局部变量尽量使用栈,全局变量、结构体成员使用堆分配等。程序员不得不花费很长的时间在不同的项目中学习、记忆这些概念并加以实践和使用。

Go语言将这个过程整合到了编译器中,命名为“变量逃逸分析”。通过编译器分析代码的特征和代码的生命周期,决定应该使用堆还是栈来进行内存分配。

1)逃逸分析

通过下面的代码来展现Go语言如何使用命令行来分析变量逃逸,代码如下:

packagemain

import"fmt"

//本函数测试入口参数和返回值情况funcdummy(bint)int{

//声明一个变量c并赋值varcintc=b

returnc}

//空函数,什么也不做funcvoid(){}

funcmain(){

//声明a变量并打印varaint

//调用void()函数void()

//打印a变量的值和dummy()函数返回fmt.Println(a,dummy(0))}

代码说明如下:

第6行,dummy()函数拥有一个参数,返回一个整型值,用来测试函数参数和返回值分析情况。

第9行,声明变量c,用于演示函数临时变量通过函数返回值返回后的情况。

第16行,这是一个空函数,测试没有任何参数函数的分析情况。

第23行,在main()中声明变量a,测试main()中变量的分析情况。

第26行,调用void()函数,没有返回值,测试void()调用后的分析情况。

第29行,打印a和dummy(0)的返回值,测试函数返回值没有变量接收时的分析情况。

接着使用如下命令行运行上面的代码:

gorun-gcflags"-m-l"main.go

使用gorun运行程序时,-gcflags参数是编译参数。其中-m表示进行内存分配分析,-l表示避免程序内联,也就是避免进行程序优化。

运行结果如下:

#


转载请注明:http://www.aierlanlan.com/rzfs/3131.html

  • 上一篇文章:
  •   
  • 下一篇文章: