Go内存分配与内存逃逸

134 阅读2分钟

www.shenshang.pro/blogs/golan…
draveness.me/golang/docs…
juejin.cn/post/686996…
www.fushengwushi.com/archives/14…

runtime.mcache 用于处理微对象和小对象的分配,它们会持有内存管理单元 runtime.mspan。

内存分配

Go 语言的内存分配器就借鉴了 TCMalloc 的设计实现高速的内存分配,它的核心理念是使用多级缓存将对象根据大小分类,并按照类别实施不同的分配策略。

多级缓存

image-20230215180010951

mspan

mspan 是go 内存管理的基本单元, 是一段连续的内存空间
内存管理模块中一共包含 67 种跨度类

classbytes/objbytes/spanobjectstail wastemax waste
1881921024087.50%
2168192512043.75%
3248192341029.24%

mcache

mcache 是go 中的每个线程的缓存, 也就是 TCMalloc 中的 Thread Cache

他和 GMP 中的 P 所绑定,TCMalloc每个线程都有一个自己的 Thread cache, 但是go 的事每个P 有一个自己的 mcache, 因为 go 中最多有GOMAXPROCS 个线程, 而P 的数量和他一样, 所以他和 P 绑定在一起刚刚好, 他的访问不需要加锁

mcentral (卖森愁)

mcentral与TCMalloc中的CentralCache类似,是所有线程共享的缓存,需要加锁访问。它按Span级别对Span分类,然后串联成链表,当mcache的某个级别Span的内存被分配光时,它会向mcentral申请1个当前级别的Span。

mheap

mheap与TCMalloc中的PageHeap类似,它是堆内存的抽象,把从OS申请出的内存页组织成Span,并保存起来。当mcentral的Span不够用时会向mheap申请内存,而mheap的Span不够用时会向OS申请内存

内存逃逸

juejin.cn/post/715581…
本该分配到函数栈空间的变量,被分配到了堆空间,称为内存逃逸

原理

  • 指向栈对象的指针不能存储在堆中
  • 指向栈对象的指针不能超过该栈对象的存活期(即指针不能在栈对象被销毁后依旧存活)

逃逸分析算法步骤

  • Golang 编译器解析 Golang 源文件后获取抽象语法树(AST)。

  • 构建有向加权图, 遍历该有向加权图寻找可能违反上述两个不变性的赋值路径, 如果一个变量的地址是储存在堆或者其他可能会超过它存活期的地方, 则该变量就会被标记为需要在堆上分配。

  • 分析函数之间的数据记录每个函数的数据流