1.CentralCache的实现
定义: static CentralFreeListPadded central_cache_[kNumClasses];
每个数组元素对应一种size class的分配请求
- 上述数组中每个元素,即CentralFreeList结构,只不过CentralFreeListPadded是CentralFreeList的一种对齐实现。
结构图如下:
2.CentralFreeList的实现
CentralCache中每个size class对应的结构(CentralFreeList),包含了三种空间管理结构:tc_slots[kMaxNumTransferEntries]、nonempty_链表、empty_链表:
TCEntry tc_slots_[kMaxNumTransferEntries];
struct TCEntry {
void *head; // Head of chain of objects.
void *tail; // Tail of chain of objects.
};
int32_t used_slots_;
int32_t cache_size_;
int32_t max_cache_size_;tc_slots_是一个数组,数组的每一个元素都是一个链表,链表的每一项都是与size class大小相对应的空闲内存空间,且链表中元素个数固定。
为什么链表中元素的个数都是固定的呢?
因为ThreadCache每次向CentralCache申请空间或归还空间时大多是一次申请或归还num_objects_to_move_[kNumClasses]个可用空间 (对于某个size class,每次从ThreadCache返回给CentralCache的对象数,都是由num_objects_to_move_[kNumClasses]所规定的),因为多个ThreadCache向CentralCache申请空间或归还空间需要加锁,一次拿一个效率太低。used_slots_反应的是当前tc_slots_中有多少空闲链表可用,换句话说就是tc_slots_数组有效元素个数。
cache_size_是对该CentralFreeList在tc_slots_上缓存大小的限定,不能无限制的缓存,当used_slots_超过cache_size_时就不能将归还的空间挂在数组中做缓存用了,需要将各个空间归还给各自的span,span在合适时候在将整个span归还给PageHeap;
max_cache_size_是cache_size_所能取得上限,因为cache_size_的值不是固定的,是根据情况动态变化的。也就是说cache_size_和max_cache_size_都是对tc_slots_数组有多少项可用所做的下标限定。
Span empty_; // Dummy header for list of empty spans
当一个span的全部空间都被分配完了的时候,就把它挂在empty_链表上Span nonempty_; // Dummy header for list of non-empty spans
当一个span只有部分空间从span分配出去时,就将它挂在noempty_链表上size_t num_spans_; // Number of spans in empty_ plus nonempty_
该CentralFreeList一共从PageHeap申请了多少个span
3.ThreadCache向CentralCache相应的CentralFreeList申请空间时
- 首先从tc_slots[kMaxNumTransferEntries]中申请空间,否则才从CentralCache中,对应的size class的nonempty链表中分配。若还不能满足分配需求,则会向PageHeap申请。
- CentralCache从PageHeap申请的span,会加入到相应size class的nonempty_链表中
- 与此同时,完成对span的格式化,即划分成若干个object,相邻object间使用指针连接
4.ThreadCache向CentralCache相应的CentralFreeList归还空间时
- ThreadCache向CentralCache返还空间时,若返回的对象数量少于num_objects_to_move_[kNumClasses]所规定的,或者tc_slots已经满了,就向CentralCache中对应的nonempty_返还,否则放入tc_slots中
- 放入nonempty_时,一个一个object地归还,即逐个将object返回到其各自所属的span中。
- 当一个span的空间,没有被任何线程使用,或者也没有放到tc_slots中,则需要将该span归还给PageHeap。
5.细节分析
void CentralFreeList::Init(size_t cl) {
....
max_cache_size_ = kMaxNumTransferEntries;