基本策略
- 每次从操作系统申请一个大块内存(比如1MB),以此减少系统调用
- 将申请到的大块内存按照特定大小预先切分成小块,构成链表
- 为对象分配内存时,只需从大小合适的链表提取一个小块即可
- 回收对象内存时,将该小块内存重新归还到原链表,以便复用
- 如果闲置内存过多,则尝试归还部分内存给操作系统,降低整体开销
tips:内存分配只管理内存块,并不关心对象状态。且它不会主动回收内存,垃圾回收器在完成清理操作后,触发内存分配器的回收操作。
内存块
管理的内存块分为两种
- span:由多个地址连续的页(page)组成的大块内存(面向内部管理)
- object: 将span按特定大小切分成多个小块,每个小块可以存储一个对象(面向对象分配)
- 按页数区分不同大小的span,需要时按页数作为索引查找。没有合适的就取更大的进行裁剪,多余部分放回管理数组。并会将地址相邻的span合并,减少碎片
_PageShift = 13
...
pageShift = _PageShift
_PageSize = 1 << _PageShift // 8kb
- 对于存储对象的object,按8字节倍数分为n种。如24字节的可以存储17-24字节的对象。初始化时,会构建存储大小和规格的对应关系,切分
_NumSizeClasses = 68
...
var class_to_size = [_NumSizeClasses]uint16{
0, 8, 16...<