前面几篇博文中已经描述了TCMalloc将内存从小到大划分成很多个固定大小的内存块,将每种大小的空闲内存块使用链表管理起来。本文就来分析下ThreadCache中空闲链表的实现。
TreadCache::FreeList的代码如下:
FreeList的成员list_是一个指向首个空闲内存块的指针,它也是链表的head。链表所有的操作均在SSL_*系列函数中实现。SSL_*系列接口如下:
SLL链表利用空闲内存本身来存储其下一个空闲内存块的地址,即将内存块的前4个字节(32位)或者8个字节(64位)用来存储next。示意图如下:
各接口实现代码在linked_list.h中:
TreadCache::FreeList的代码如下:
- class FreeList {
- private:
- void* list_; // Linked list of nodes
- #ifdef _LP64
- // On 64-bit hardware, manipulating 16-bit values may be slightly slow.
- uint32_t length_; // Current length.
- uint32_t lowater_; // Low water mark for list length.
- uint32_t max_length_; // Dynamic max list length based on usage.
- // Tracks the number of times a deallocation has caused
- // length_ > max_length_. After the kMaxOverages'th time, max_length_
- // shrinks and length_overages_ is reset to zero.
- uint32_t length_overages_;
- #else
- // If we aren't using 64-bit pointers then pack these into less space.
- uint16_t length_;
- uint16_t lowater_;
- uint16_t max_length_;
- uint16_t length_overages_;
- #endif
- public:
- void Init() {
- list_ = NULL;
- length_ = 0;
- lowater_ = 0;
- max_length_ = 1;
- length_overages_ = 0;
- }
- // Return current length of list
- size_t length() const {
- return length_;
- }
- // Return the maximum length of the list.
- size_t max_length() const {
- return max_length_;
- }
- // Set the maximum length of the list. If 'new_max' > length(), the
- // client is responsible for removing objects from the list.
- void set_max_length(size_t new_max) {
- max_length_ = new_max;
- }
- // Return the number of times that length() has gone over max_length().
- size_t length_overages() const {
- return length_overages_;
- }
- void set_length_overages(size_t new_count) {
- length_overages_ = new_count;
- }
- // Is list empty?
- bool empty() const {
- return list_ == NULL;
- }
- // Low-water mark management
- int lowwatermark() const { return lowater_; }
- void clear_lowwatermark() { lowater_ = length_; }
- void Push(void* ptr) {
- SLL_Push(&list_, ptr);
- length_++;
- }
- void* Pop() {
- ASSERT(list_ != NULL);
- length_--;
- if (length_ < lowater_) lowater_ = length_;
- return SLL_Pop(&list_);
- }
- void* Next() {
- return SLL_Next(&list_);
- }
- void PushRange(int N, void *start, void *end) {
- SLL_PushRange(&list_, start, end);
- length_ += N;
- }
- void PopRange(int N, void **start, void **end) {
- SLL_PopRange(&list_, N, start, end);
- ASSERT(length_ >= N);
- length_ -= N;
- if (length_ < lowater_) lowater_ = length_;
- }
FreeList的成员list_是一个指向首个空闲内存块的指针,它也是链表的head。链表所有的操作均在SSL_*系列函数中实现。SSL_*系列接口如下:
- void *SLL_Next(void *t);//取t的下一块空闲内存。t也是一个空闲内存块。
- void SLL_SetNext(void *t, void *n);//设置空闲内存块t的下一个空闲内存快n。
- void SLL_Push(void **list, void *element);//在链表最前面插入一个空闲内存块element。
- void *SLL_Pop(void **list);//取出链表中第一个空闲内存块。
- void SLL_PopRange(void **head, int N, void **start, void **end);//取出链表中前面N个空闲内存块。
- void SLL_PushRange(void **head, void *start, void *end);//在链表前面插入从start到end一个链表。
- size_t SLL_Size(void *head);//计算链表的长度。

各接口实现代码在linked_list.h中:
- inline void *SLL_Next(void *t) {
- return *(reinterpret_cast<void**>(t));//将当前内存块重新解释为一个二级指针,它指向一个void*,即空闲内存块。再通过*操作符获取它指向下一块空闲内存的地址。
- }
- inline void SLL_SetNext(void *t, void *n) {
- *(reinterpret_cast<void**>(t)) = n;
- }
- inline void SLL_Push(void **list, void *element) {
- SLL_SetNext(element, *list);
- *list = element;
- }
- inline void *SLL_Pop(void **list) {
- void *result = *list;
- *list = SLL_Next(*list);
- return result;
- }
- // Remove N elements from a linked list to which head points. head will be
- // modified to point to the new head. start and end will point to the first
- // and last nodes of the range. Note that end will point to NULL after this
- // function is called.
- inline void SLL_PopRange(void **head, int N, void **start, void **end) {
- if (N == 0) {
- *start = NULL;
- *end = NULL;
- return;
- }
- void *tmp = *head;
- for (int i = 1; i < N; ++i) {
- tmp = SLL_Next(tmp);
- }
- *start = *head;
- *end = tmp;
- *head = SLL_Next(tmp);
- // Unlink range from list.
- SLL_SetNext(tmp, NULL);
- }
- inline void SLL_PushRange(void **head, void *start, void *end) {
- if (!start) return;
- SLL_SetNext(end, *head);
- *head = start;
- }
- inline size_t SLL_Size(void *head) {
- int count = 0;
- while (head) {
- count++;
- head = SLL_Next(head);
- }
- return count;
- }