【Go进阶训练营】内存分配原理
创始人
2025-05-30 21:09:38
0

前言

上一篇,我介绍了一下Go的垃圾回收原理,补一下对象的内存是如何分配的。一个对象是 内存分配->使用->垃圾回收 完成一个流程。

堆栈 & 逃逸分析

Go语言中有两个地方可以进行分配内存,分别是堆和栈。
:一个全局的堆空间,堆区的内存一般由编译器和工程师自己共同进行管理分配,由Runtime Gc来释放。
:每个goroutine自身的栈空间,栈一本都由编译器自动进行分配和释放,一般会随着入栈和出栈进行销毁。
区别是:栈分配廉价,而堆分配昂贵。
在这里插入图片描述

一个简单的问题。

普通的变量是在堆还是栈上?
这里就引出的另外一个问题:逃逸分析。
逃逸:一句话就是变量的作用域超出来所在的栈区,就是逃逸。
在编译期由静态代码分析来决定一个值是否能被分配在栈帧上,还是需要“逃逸”到堆上。

逃逸分析的好处

  • 减少GC的压力,栈上的变量会随着出栈而将内存回收,减少堆内存的GC
  • 减少内存碎片的压力
  • 减轻堆内存的分配压力
func main() {number := getNumber()fmt.Println(number)
}func getNumber() *int {num := rand.Intn(100)return &num
}

从图中可以看出,当main函数想要调用getNumber()函数的时候,必定会从main栈帧到getNumber()栈帧,而如果想通过调用传递参数,比如通过堆空间地址的引用。所以需要将num变量所分配的地址指向堆内存空间中。这就是逃逸分析技术。
也就是:Go 查找所有变量超过当前函数栈侦的,把它们分配到堆上,避免 outlive 变量
在这里插入图片描述

逃逸分析案例

  • 一个值被分享到函数范围外
  • for循环外声明,循环内分配 等等

连续栈

分段栈:Go应用程序运行时,每个goroutine都维护着一个自己的栈区,别的goroutine不能使用,初始大小为2KB,运行期间可以动态的增长和收缩。
hot split问题:但是分段栈存在hot split问题,如果一个栈空间满了,会出发扩容,函数返回时会自动销毁,但是如果这个函数在一个循环中,会频繁的分配/销毁,性能会下降。
在这里插入图片描述
连续栈:为了解决以上问题,采用连续栈,其实有点像java中的ArrayList扩容机制,默认分配2KB,如果不够的话,那么会创建一个新的空间*2,将数据直接迁移过去,引用地址也进行修改。而且支持动态的缩容。具体的扩容和缩容算法这里不具体细说,感兴趣的可以google。

  • runtime.newstack 分配更大的栈内存空间
  • runtime.copystack 将旧栈中的内容复制到新栈中
  • 将指向旧栈对应变量的指针重新指向新栈
  • runtime.stackfree 销毁并回收旧栈的内存空间
    在这里插入图片描述

内存结构

内存布局

  • page:内存页,一个8K大小的内存空间,Go与操作系统进行内存申请和释放,都是按照page为单位的。
  • span:内存块,由一个或者多个page内存页进行组成。
  • size class: 空间规格,一个span由一个size class,标记当前span内存的使用情况,如何使用等。
  • object : 对象,用来存储一个变量的内存空间,span 初始化的时候,被切割成等大的object。

总结:span = 一个空间规则描述信息(size class) + 至少一个page内存页= 多个object对象
在这里插入图片描述

在这里插入图片描述

内存布局

在这里插入图片描述
一般小对象通过 mspan 分配内存;大对象则直接由 mheap 分配内存。

  • Go 在程序启动时,会向操作系统申请一大块内存,由 mheap 结构全局管理(现在 Go 版本不需要连续地址了,所以不会申请一大堆地址)
  • Go 内存管理的基本单元是 mspan,每种 mspan 可以分配特定大小的 object
  • mcache, mcentral, mheap 是 Go 内存管理的三大组件,mcache 管理线程在本地缓存的 mspan;mcentral 管理全局的 mspan 供所有线程

分配规则

三种级别进行分配。

  • 小于 32kb 内存分配
  • 小于 16b 内存分配
  • 大于 32kb 内存分配

小结

本文从Go内存结构,堆栈两个出发,然后引出逃逸分析,以及其特点。接着分析了分段栈的缺点,引入了连续栈。最后是内存的布局,以及分配原则,主要围绕mcache、mcentral、mheapGo内存管理的三大组件。

资料:Go训练营。

相关内容

热门资讯

50岁生日祝福语 五十岁生日... 50岁生日祝福语 五十岁生日贺词人生感叹,10岁时,无忧无虑,天真无邪,20岁时,忙碌奔波,辛苦工作...
<Linux开发> linux... <Linux开发> linux开发工具-之-CMake简单例程[再见] Cmake相关文章如下: 1...
国庆节简单祝福语 2022年国庆节简单祝福语(精选155句)  在现实生活或工作学习中,大家都不可避免地会接触到祝福语...
母亲节丈母娘祝福语 母亲节丈母娘祝福语(精选175句)  在学习、工作或生活中,许多人都有过写祝福语的经历,对祝福语都不...
同事离职祝福语 同事离职祝福语15篇  在平平淡淡的学习、工作、生活中,大家都用到过祝福语吧,祝福语是指对人们的美好...
JAVASE(3.18) 目录 ​编辑 1.抽象类和抽象方法 2.接口 3.比较自定义类型 学习不要眼高手低,...
教师节优美祝福语短信 教师节优美祝福语短信55条  因为有了您,世界才会如此美丽,因为有了您,我的生命才会如此多彩!医生治...
去除Spire.Doc导出字样... //去除Spire.Doc导出字样信息try (FileInputStream in = n...
给老师的春节贺卡祝福语 给老师的春节贺卡祝福语170句  在我们平凡的日常里,要用到祝福语的情况还是蛮多的,祝福语可以起到增...
父亲节暖心祝福语 父亲节暖心祝福语  在日复一日的学习、工作或生活中,大家都用到过祝福语吧,祝福语有助于促进交流,拉近...
温馨教师节祝福语 2020年温馨教师节祝福语集锦45条  您辛劳了,教师节到了,您也该歇一歇了,坐着接接电话看看短信吧...
《RabbitMQ高阶知识》—... 《RabbitMQ高阶知识》— 消息可靠性 文章目录《RabbitMQ高阶知识》— 消息可靠性&#x...
Kubernetes(5):P... 我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期,它主要包含下面的过程: pod创建...
学校领导新年元旦祝福语 学校领导新年元旦祝福语校师生员工们:  新年的钟声Ji荡着神州大地,岁月的航船开启着新的征程,我们即...
hugginface相关数据集... swaption2009/20k-en-zh-translation-pinyin-hsk 翻译 S...
孙子满月酒贺词 孙子满月酒贺词  宝宝降生,我前来贺喜,愿新生的小宝贝给你们带来数不尽的`快乐,祝小宝贝身体健康,茁...
温馨端午节祝福语句 常用温馨端午节祝福语句70句  端午快乐,幸福甜蜜!下文是小编特意为各位读者准备的温馨端午节祝福语句...
SQL常用语法语句 文章目录1. 什么是sql语句?1.1 DDL(数据定义语言)用法2. 什么是数据库对...
暖心重阳节祝福语短信 2020年暖心重阳节祝福语短信大汇总77句  九九重阳节日到,我的短信首先到,登高望远先敬老,赏菊插...
经典七夕祝福语 经典七夕祝福语99句  枯草连天太苍茫,小路白杨一行行。牵手偶因手太凉,曾经一起看夕阳。夕阳挂在柳梢...