Loading... # 0x01 <div class="tip inlineBlock warning"> 本文基于 **Go 1.14.12** 注意信息时效,特别是与 **Go 1.11 版本** 之前会有很大的区别 </div> 因为内存管理比较抽象,网络上各种大佬的文章又有点过于深奥,没看懂整个内存管理的过程去做源码分析相当困难,这里仅抛砖引玉,画几张图简单介绍一下内存管理机制,真正的细节还得看文后各位大佬们的文章啊~  # 栈分配 分配内存前首先就是要确定是在栈上分配还是堆上分配,一般来说函数上的内存都是在栈上分配。  但是 Go 语言有特殊情况,在编译阶段会对函数进行逃逸分析,逃逸的对象会在堆上分配内存。  检测没有逃逸后,分配一个栈帧供调用方使用  当函数返回后,即刻销毁  # 堆分配 一般我们说的内存管理都是指的 **堆上内存** 管理,因为从堆上分配内存的成本很高,且要进行垃圾回收等操作。Go 语言中,将堆内存分配按大小分为了 `tiny`、`small` 和 `large` 三级。 > - Tiny : size < 16 bytes && has no pointer(noscan) > - Small :has pointer(scan) || (size >= 16 bytes && size <= 32 KB) > - Large : size > 32 KB ## tiny 为了减少分配对象锁竞争,每个 P 上都有一个`线程缓存 mcache`,其中包含`alloc`、`tiny`和`tiny offset`,其中`tiny`为含有总大小`64byte`的可分配内存 `tiny elem` 的微分配器,如果`tiny elem`还有富余,就会直接从`tiny elem`中分配内存,并移动其维护的 offset。  如果 `tiny elem` 中的内存不够分配了,则 P 会用 `alloc`结构中找一个`64bytes`的空间作为新的 `tiny elem`。然后再在新的 `tiny elem` 中划分内存。   还有一种情况,就是 `mcache` 内的对应内存大小的槽空间也满了,这时候只能像更上层 `mheap` 去申请新的槽位了。`mheap` 会先检查自己的 `arenes` 中有没有剩余,如果没有就向操作系统申请。   ## small `small`对象分配比 `tiny` 更简单,因为只需要去 `alloc` 上分配一个向上取整的内存块。  ## large 分配 `large` 对象的过程更为简单,直接向 `mheap` 申请对应大小的内存即可  # Reference [Go runtime剖析系列(一):内存管理](https://zhuanlan.zhihu.com/p/323915446) [Go1.16 新特性:详解内存管理机制的变更,你需要了解](https://eddycjy.com/posts/go/go1.16-3/) [Go 语言设计与实现 - 7.1 内存分配器](https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-memory-allocator/) 最后修改:2021 年 08 月 06 日 12 : 35 PM © 允许规范转载 赞赏 如果觉得我的文章对你有用,请随意赞赏 赞赏作者 支付宝微信