Golang内存分配机制 作者: nbboy 时间: 2021-05-10 分类: 软件架构,软件工程,Golang # Golang内存分配机制 Go的内存分配分为微内存分配,小内存分配,大内存分配,微内存为小于16字节的内存分配,小内存则为大于16字节小于32KB的内存分配,大内存是大于32KB的内存分配。 ## Page与Span 在Golang中一个**内存页**为8K,其为Golang内存分配器以此为倍数单位大小去申请,比如申请16G。Span为一个或者多个连续的内存页组成,可以想象成如下结构: span.pn ## 小内存分配 ### mCache Go的内存分配采用的类似TCMalloc一样的分配策略,就是对需要分配的内存按照尺寸大小进行分级,按照不同的SizeClass分为<=8KB,<=16KB,<=32KB。 一个Goroutine去申请内存时,就是在其对应的P的mCache中去申请,申请的基本单元称为mSpan,根据mSpan的大小找到最接近其的内存块返回即可。因为其实在P内部去分配的,所有过程中不需要加全局锁,性能会快很多。 mCache.pn ### mCentral 当然mCache内存块也会分配光,所以它会向mCentral去要,mCentral有两个双向链表组成,一个用来可以被用来分配的内存块组(Non Empty List),另外一个用来存放已经分配出去的内存块组(Empty List),但是mCentral分配和释放的时候是需要加全局锁的,因为它也是所有P共享的。比如分配的流程是这样的: 1. 获得全局锁GL 2. 在Non Empty List中获得一块内存 3. 在Empty List记录下这块内存 4. 释放全局锁GL mCentral.pn ### mHeap 当mCentral也没有多余的内存的时候,就需要向mHeap进行申请,而mHeap中存放的是未被切割成一块一块的大的内存块,其称为Arena内存块,在mHeap中以二维数组的形式进行存放。 mHeap.pn ## 微内存分配 对于很多频繁申请并且尺寸很小的 内存需求我们叫Tiny对象,其如果每次都是申请然后马上释放,这样会造成空间浪费,所以Golang对这块做了一些优化。想小字符串,或者临时的逃逸变量等等,都会按照微内存来分配,用完之后该空间还能继续使用。 可以把很多Tiny对象打包成一个大对象,然后统一分配一个小内存给该区域就可以。 tiny_obj.pn ## 大内存分配 大内存指的就是大于32Kb的内存,这部分内存分配频率不会太高,但是尺寸可能往往很大,所以直接让mHeap去分配,如果mHeap中的Arena内存块不够用,再向操作系统申请虚拟内存即可。 ## 总结 Golang内存分配主要思想还是按照不同的尺寸去获取最适合的内存块,和Memcached的Slab内存分配策略有一些像,主要目的就是减少内存碎片。 ### 参考 毛大的PPT https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-memory-allocator/ https://zhuanlan.zhihu.com/p/59125443 未读 标签: Golang, 内存, 内存分配
评论已关闭