内存分配器TCMalloc
一 内存分配器
1.0 Golang的内存分配器TCMalloc
Go的内存分配基于TCMalloc(Thread-Cacing Malloc,Google开发的一款高性能内存分配器),源码位于runtime/malloc.go
。但是经过多年发展,Go的内存分配算法已经大幅进化,但是学习TCMalloc仍然能看到一些Go内存分配的基础。
Go采用离散式空闲列表算法(Segregated Free List)分配内存,主要核心算法思想是:
- 线程私有性
- 内存分配粒度
1.1 线程私有性
TCMalloc内存管理体系分为三个层次:
- ThreadCache:一般与负责小内存分配,每个线程都拥有一份ThreadCache,理想情况下,每个线程的内存申请都可以在自己的ThreadCache内完成,线程之间无竞争,所以TCMalloc非常高效 ,这既是TCMalloc的线程私有性
- CentralCache:内部含有多个CentralFreelist
- PageHeap:与负责大内存分配,是中央堆分配器,被所有线程共享,可以与操作系统直接交互(申请、释放内存),大尺寸内存分配会直接通过PageHeap分配
TCMalloc具备线程私有性质,然而现实往往是骨感的!ThreadCache中内存不足时,还需要其他2个组件帮助,内存的分配、释放从上述三个层级中依次递进:当最小的Thread层分配内存失败,则从下一层的CentralCache中分配一批补充上来。
CentralFreeList是TheadCache和PageHeap之间协调者。
- 分配内存:CentralFreeList会将PageHeap中的内存切分为小块,分配给ThreadCache。
- 释放内存:CentralFreeList会获取从ThreadCache中回收的内存,归还给PageHeap。
如图所示:
![]
(runtime-03.svg)
1.2 内存分配粒度
内存分配调度的最小单位也称为粒度,TCMalloc有两种分配粒度:
- span:用于内部管理。span是由连续的page内存组成的一个大块内存,负责分配超过256KB的大内存
- object:用于面向对象分配。object是由span切割成的小块,其尺寸被预设了一些规格(class),如16B,32B(88种),不会大于256KB(交给了span)。同一个span切出来的都是相同的object。
贴士:ThreadCache和CentralCache是管理object的,PageHeap管理的是span。
如图所示(每个class对应一个链表):
![] (runtime-04.svg)
在申请小内存(小于256KB时),TCMalloc会根据申请内存的大小,匹配到与之大小最接近的class中,如: