概要
预申请的内存划分为spans 、 bitmap 、 arena三部分。
arena为堆区,应用区中的内存从其中分配。大小为521GB,划分成一个一个的page,每个page大小为8KB,一共有 512GB/8KB = 64M个page。
spans存放span指针,每个指针对应一个或者多个arena,span大小为 512GB/8KB * 8byte = 512MB。
bitmap由arena计算出来,主要用于GC。
span
span用于管理arena页关键的数据,每个span包含一个或者多个连续页。为满足小对象分配,会将span中的一页划分为更小的粒度,而对于超过页大小则会通过多页实现。span是内存管理的基本单位。
class
每一类代表一个固定大小的对象以及span的大小。通常class越大,span占用堆的字节数越多。每个class只能包括一个对象。
class最大值为66,即最大的对象大小为32KB,如果超过32KB,则class 为0 。
cache
mcentral是管理span的数据结构。线程需要内存时,需要想mcentral申请,为避免多线程申请内存加锁,所以为每个线程配备了span缓存,称为cache。
cache的数据结构中,定义了数组大小为class总数二倍的mspan指针数组。每种class类型都有两组span列表,第一组列表包含指针,第二组不包含,主要用于提高GC扫描效率。
根据GC是否扫描,将对象分为scan类以及noscan类,其中scan类即为包含指针的类。
central
cache为单个线程服务,而central为全局资源、多个线程服务。
当线程内存不足时向central申请,当线程释放内存时又会回收进central。
线程从central回去span的步骤:
- 加锁。
- 从nonempty列表中取出一个可用的span。
- 将span加入到empty列表。
- 将span发送给线程。
- 解锁
- 将span写入cache。
线程归还span给central
- 加锁。
- 将span从empty列表取出。
- 将span加入nonempty列表。
- 解锁。
heap
每种mcentral管理一种class,而mcentral集合存放于mheap数据结构中。
内存分配
分配对象大小 | 分配类型 |
---|---|
(0 , 16B)不包含指针 | Tiny分配 |
(0 , 16B)包含指针 | 正常分配 |
(16B , 32KB) | 正常分配 |
(32KB , +∞ ) | 大对象分配 |
申请size为n的内存流程:
- 获取当前线程的cache。
- 通过size计算出合适的class的ID。
- 从cache的alloc[class]链表中查询可用span。
- 如果有可用span,则从mcentral申请一个span加入cache。
- 如果没有可用span,则从mheap中申请一个新的span加入cache。
- 从该span中获取空闲对象地址并返回。