分类: LINUX
2011-10-08 16:05:27
下面我们来看看FetchFromSpans和Populate两个函数。FetchFromSpans首先判断CentralFreeList的nonempty_列表中是否有可用的span如果没有则返回NULL,否则取nonempty_第一个span,然后将span中切出一个obj,并调整span->objects指正,如果span已经被切割干净,那么把这个span从nonempty列表中分离出来放入empty列表。
void* CentralFreeList::FetchFromSpans() {
if (tcmalloc::DLL_IsEmpty(&nonempty_)) return NULL;
Span* span = nonempty_.next;
ASSERT(span->objects != NULL);
span->refcount++;
void* result = span->objects;
span->objects = *(reinterpret_cast
if (span->objects == NULL) {
// Move to empty list
tcmalloc::DLL_Remove(span);
tcmalloc::DLL_Prepend(&empty_, span);
Event(span, 'E', 0);
}
counter_--;
return result;
}
Populate函数通过Static::pageheap中New出需要的空间,首先通过Static::sizemap()->class_to_pages将size转换为npages。然后通过函数Static::pageheap()->New从pageheap获取npages个页面,然后如果span获取成功,那么将他插入pagemap_这颗raidx tree。如果span为NULL那么代表分配失败返回,返回前先获取前面释放的CentralFreeList的锁。如果分配成功,那么将这个span中的page插入pagemap_cache_这个二元组。最后通过一个while循环将整个span拆分成一个个的obj并通过*tail = ptr; 和 tail = reinterpret_cast
void CentralFreeList::Populate() {
// Release central list lock while operating on pageheap
lock_.Unlock();
const size_t npages = Static::sizemap()->class_to_pages(size_class_);
Span* span;
{
SpinLockHolder h(Static::pageheap_lock());
span = Static::pageheap()->New(npages);
if (span) Static::pageheap()->RegisterSizeClass(span, size_class_);
}
if (span == NULL) {
MESSAGE("tcmalloc: allocation failed", npages << kPageShift);
lock_.Lock();
return;
}
ASSERT(span->length == npages);
// Cache sizeclass info eagerly. Locking is not necessary.
// (Instead of being eager, we could just replace any stale info
// about this span, but that seems to be no better in practice.)
for (int i = 0; i < npages; i++) {
Static::pageheap()->CacheSizeClass(span->start + i, size_class_);
}
// Split the block into pieces and add to the free-list
// TODO: coloring of objects to avoid cache conflicts?
void** tail = &span->objects;
char* ptr = reinterpret_cast
char* limit = ptr + (npages << kPageShift);
const size_t size = Static::sizemap()->ByteSizeForClass(size_class_);
int num = 0;
while (ptr + size <= limit) {
*tail = ptr;
tail = reinterpret_cast
ptr += size;
num++;
}
ASSERT(ptr <= limit);
*tail = NULL;
span->refcount = 0; // No sub-object in use yet
// Add span to list of non-empty spans
lock_.Lock();
tcmalloc::DLL_Prepend(&nonempty_, span);
counter_ += num;
}
我们在看一下函数= Static::pageheap()->New,其中kMaxPages为256。
Span* PageHeap::New(Length n) {
ASSERT(Check());
ASSERT(n > 0);
// Find first size >= n that has a non-empty list
for (Length s = n; s < kMaxPages; s++) {//从size为npage的freelist开始查找,如果不符合那么查找比n大的下一个freelist
Span* ll = &free_[s].normal;// 首先获取normal list,同一个size的span分为两类,normal和return,normal就是一切正常的span,return代表内存已经返回给系统的span
// If we're lucky, ll is non-empty, meaning it has a suitable span.
if (!DLL_IsEmpty(ll)) {//如果normal list为空
ASSERT(ll->next->location == Span::ON_NORMAL_FREELIST);//通过span的location来判断span是怪哉freelist上,如果是,那么用Carve吧这个span切出。如果在normal队列里面分配失败,那么从returned队列里面切出来。
return Carve(ll->next, n);
}
// Alternatively, maybe there's a usable returned span.
ll = &free_[s].returned;
if (!DLL_IsEmpty(ll)) {
ASSERT(ll->next->location == Span::ON_RETURNED_FREELIST);
return Carve(ll->next, n);
}
// Still no luck, so keep looking in larger classes.
}
如果以上都没有成功,那么我们的祈求AllocLarge从系统分配了
Span* result = AllocLarge(n);
if (result != NULL) return result;
// Grow the heap and try again
//继续尝试,首先增长Heap,尝试再次分配。
if (!GrowHeap(n)) {
ASSERT(Check());
return NULL;
}
return AllocLarge(n);
}