企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
Go中的内存分类并不像TCMalloc那样分成小、中、大对象,但是它的小对象里又细分了一个Tiny对象,Tiny对象指大小在1Byte到16Byte之间并且不包含指针的对象。 小对象和大对象只用大小划定,无其他区分。 大对象指大小大于32kb.小对象是在mcache中分配的,而大对象是直接从mheap分配的,从小对象的内存分配看起。 Go的内存分配原则: Go在程序启动的时候,会先向操作系统申请一块内存(注意这时还只是一段虚拟的地址空间,并不会真正地分配内存),切成小块后自己进行管理。 申请到的内存块被分配了三个区域,在X64上分别是512MB,16GB,512GB大小。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/134.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/134.jpg) arena区域就是我们所谓的堆区,Go动态分配的内存都是在这个区域,它把内存分割成8KB大小的页,一些页组合起来称为mspan。 bitmap区域标识arena区域哪些地址保存了对象,并且用4bit标志位表示对象是否包含指针、GC标记信息。bitmap中一个byte大小的内存对应arena区域中4个指针大小(指针大小为 8B )的内存,所以bitmap区域的大小是`512GB/(4*8B)=16GB`。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/135.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/135.jpg) [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/136.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/136.jpg) 此外我们还可以看到bitmap的高地址部分指向arena区域的低地址部分,这里bitmap的地址是由高地址向低地址增长的。 spans区域存放mspan(是一些arena分割的页组合起来的内存管理基本单元,后文会再讲)的指针,每个指针对应一页,所以spans区域的大小就是`512GB/8KB*8B=512MB`。 除以8KB是计算arena区域的页数,而最后乘以8是计算spans区域所有指针的大小。创建mspan的时候,按页填充对应的spans区域,在回收object时,根据地址很容易就能找到它所属的mspan。