首页 > 系统相关 >栈内存和堆内存概念、内存逃逸分析

栈内存和堆内存概念、内存逃逸分析

时间:2023-12-08 17:47:24浏览次数:26  
标签:函数 元素 回收 概念 逃逸 内存 分配

为了让程序员更好地专注于业务代码的实现,Go 语言增加了垃圾回收机制,自动地回收不再使用的内存。Go 语言有两部分内存空间:栈内存和堆内存。

1. 栈内存
栈只允许往线性表的一端放入数据,之后在这一端取出数据,按照后进先出(LIFO, Last In First Out )的顺序,如图所示。

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

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

栈内存由编译器自动分配和释放,开发者无法控制。栈内存一般存储函数中的局部变量、参数等,函数创建的时候,这些内存会被自动创建;函数返回的时候,这些内存会被自动释放。

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

func calc(a, b int) int {
    var c int
    c = a * b

    var x int
    x = c * 10

    return x
}

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

2. 堆内存
堆在内存分配中类似于往一个房间里摆放各种家具,家具的尺寸有大有小。

分配内存时,需要找一块足够装下家具的空间再摆放家具。经过反复摆放和腾空家具后,房间里的空间会变得乱七八糟,此时再往空间里摆放家具会存在虽然有足够的空间,但各空间分布在不同的区域,无法有一段连续的空间来摆放家具的问题。

此时内存分配器就需要对这些空间进行调整优化,堆适合不可预知大小的内存分配。但是为此付出的代价是分配速度较慢,而且会形成内存碎片 。

堆内存的生命周期比栈内存要长,如果函数返回的值还会在其他地方使用,那么这个值就会被编译器自动分配到堆上。堆内存相比栈内存来说,不能自动被编译器释放,只能通过垃圾回收器才能释放,所以栈内存效率会很高。

3. 逃逸分析
既然栈内存的效率更高,肯定是优先使用栈内存。那么 Go 语言是如何判断一个变量应该分配到堆上还是栈上的呢?这就需要逃逸分析了。下面我通过一个示例来讲解逃逸分析,代码如下:

package main

func main() {
    newString()
}

func newString() *string{
   s:=new(string)
   *s = "wohu"
   return s
}

现在通过逃逸分析来看下是否发生了逃逸,命令如下:

go build -gcflags="-m -l" main.go

-m 表示打印出逃逸分析信息;
-l 表示禁止内联,可以更好地观察逃逸;

从以上输出结果可以看到,发生了逃逸,也就是说指针作为函数返回值的时候,一定会发生逃逸。

逃逸到堆内存的变量不能马上被回收,只能通过垃圾回收标记清除,增加了垃圾回收的压力,所以要尽可能地避免逃逸,让变量分配在栈内存上,这样函数返回时就可以回收资源,提升效率。

对 newString 函数进行了避免逃逸的优化:

func newString() string{
   s:=new(string)
   *s = "wohu"
   return *s
}

通过分析结果可以看到,虽然还是声明了指针变量 s,但是函数返回的并不是指针,所以没有发生逃逸。

逃逸分析是判断变量是分配在堆上还是栈上的一种方法,在实际的项目中要尽可能避免逃逸,这样就不会被 GC 拖慢速度,从而提升效率。

标签:函数,元素,回收,概念,逃逸,内存,分配
From: https://www.cnblogs.com/beatle-go/p/17888689.html

相关文章

  • 从概念到实践,带你掌握层次递归查询
    本文分享自华为云社区《GaussDB数据库SQL系列-层次递归查询》,作者:Gauss松鼠会小助手2。一、前言层次递归查询是一种常见的SQL查询方式,特别是在一些层次化的数据存储结构中经常用到。本文主要以GaussDB数据库为实验平台,为大家讲解其使用方法。二、GuassDB数据库层次递归查询概......
  • [电脑装机] 内存篇
    [装机|配置升级]内存篇内存也称内存储器和主存储器,它用于暂时存放CPU中的运算数据,与硬盘等外部存储器交换的数据。一、部分内存参数我们一般能在内存条(SDRAM)的标签上的可以看到型号和参数。型号是内存条厂商自己定义的,不同厂商的定义规则不一致,一般可以通过型号识别内存参......
  • 麒麟系统一直free命令看内存占用90%但是top命令看每个程序占用内存只有20%,怎么查找什
    麒麟系统一直free命令看内存占用90%但是top命令看每个程序占用内存只有20%,怎么查找什么问题导致的这种情况 这种情况可能是因为Linux系统的内存管理机制导致的。free命令和top命令使用不同的方式来报告内存使用情况,因此可能会看到不同的结果。free命令显示的......
  • 共享内存技术调研
    共享内存技术调研1.     研究目的在调研仿真分布式解决方案时遇到一个问题,在服务器中不同软件之间如何高效的进行通讯,这里涉及到了不同的操作系统(windows和Linux),不同的使用功能(虚实融合,数字仿真),需求不同需要的信息传递效率要求不同,因此需要调研现有的技术,找到适合使用......
  • 气象中和风相关的概念
    http://colaweb.gmu.edu/dev/clim301/lectures/wind/wind-uv东西风U单位:米/秒(m/s),通常正值为西风,负值为东风。南北风V单位:米/秒(m/s),通常正值为南风,负值为北风。U为正值为西风的意思是风从西边吹来,真实的风向箭头指向右边,U为负值风从东边吹来,箭头指向左边。V为正值为南风风从南......
  • Spring入门03Spring核心概念、DI、IOC入门案例
    Spring核心概念IoC/DIIoC容器Bean IOC入门案例IoC入门案例思路分析  IoC入门案例实现   DI入门案例 DI入门案例思路分析DI入门案例实现  ......
  • 函数(1)基本概念,参数,调用,声明和定义
    一、C语言中函数分为库函数和自定义函数库函数:C语言本身提供的函数,有函数名、返回值类型和函数参数常用的库函数有IO函数(stdio.h),字符串操作函数(strlen),字符操作函数(大小写),内存操作函数(memset),时间/日期函数(time),数学函数(sqrt)以及其他库函数。intmain(){ chararr1[]=......
  • ROS2的概念
    ROS2中每一个节点也是只负责一个单独的模块化的功能(比如一个节点负责控制车轮转动,一个节点负责从激光雷达获取数据、一个节点负责处理激光雷达的数据、一个节点负责定位等等)节点间的通信方式:1.话题topics 是一种轻量级的通信方式,用于实现发布-订阅模式,即一个节点发布数据,......
  • DDR内存基础知识
    一、DDR基础知识1.几个频率(1)核心频率:真实运行频率。(2)倍增系数:DDR通过数据预取技术放大速率,每代ddr倍率是固定的,ddr=2,ddr2=4,ddr3=8,ddr4=8,ddr5=16(3)有效频率;厂商标注的频率,可以理解为数据传输速率。厂商也想逐步淡化其它频率的概念,只让我们记住有效频率。其实......
  • Solidity基本概念学习2
    文档:https://solidity-by-example.org/视频教程:https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p说明看视频没注意有文档,前面写了一篇好多废话,之后结合文档+视频去做笔记和写代码,做记录...常量(constant)常量是不能修改的......