这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
GO内存分配
GO程序在启动的时候向操作系统申请一个内存,将申请到的内存分配为三个大区域512MB,16GB,512GB。
arena就是堆区,对象动态分配内存的地方,按8KB拆分成页,多个页构成一个mspan。
左边低地址,右边高地址
bitmap的大小有arena决定的,bitmap用于标识area区域中一个byte对应arena中的4个指针(指针大小8B),所以bitmap大小为512GB/(4*8B)=16GB.
bitmap和arena紧靠,arena由低地址向高地址生长,bitmap的地址是由高地址向低地址增长的。
spans区域存放指针,指针指向mspan,mspan最小就是一页8k,一个指针8B,所以spans的大小为512GB/8KB*8B=512MB。那么什么是mspan呢?
mspan:
也就是内存分块。将arena分成很多块。
Go中内存管理的基本单元,是由一片连续的8KB的页组成的大块内存。mspan是双端链表的结点。mspan中存放object,根据每种object的大小不同,又可以给mspan分为很多类,object大小相近的放在一起,大对象的存储可以在堆上直接分配。
mcache:
每个goroutine都会有一块缓存。可以解决Gorouine之间的竞争问题,不会消耗锁资源,
mcentral:
mcentral被所有的工作线程共同享有,存在多个Goroutine竞争的情况,因此会消耗锁资源。
mheap
mheap:代表Go程序持有的所有堆空间,Go程序使用一个mheap的全局对象_mheap来管理堆内存。
线上生成很多小对象,分配内存耗时,
字节跳动给每个g(goroutine)分配一个GAB,类似于java的给线程预分配一个空间。GAB类似于一个大对象。
GAB有点像Java的G1垃圾收集器。
总结:
内存分配是一个复杂问题,GO程序启动会申请一大块内存,然后又成三个大块,然后又是mspan小块,mcache, mcentral, mheap是Go内存管理的三大组件,层层递进。小对象和大对象的分配比较特殊。