分类: LINUX
2011-10-08 16:06:37
我们在看看Carve函数,Carve函数将span从normal list中切出,返回给Populate。首先将span的location为置位为Span::IN_USE,然后判断这个span的长度是否真好为n,如果大于n那么将span切割成两个span,新切出来的span叫做leftover,然后通过RecordSpan将span添加到pagemap_中。然后通过PrependToFreeList将这个span根据location添加到normal或者returnd队列。
Span* PageHeap::Carve(Span* span, Length n) {
ASSERT(n > 0);
ASSERT(span->location != Span::IN_USE);
const int old_location = span->location;
RemoveFromFreeList(span);
span->location = Span::IN_USE;
Event(span, 'A', n);
const int extra = span->length - n;
ASSERT(extra >= 0);
if (extra > 0) {
Span* leftover = NewSpan(span->start + n, extra);
leftover->location = old_location;
Event(leftover, 'S', extra);
RecordSpan(leftover);
PrependToFreeList(leftover); // Skip coalescing - no candidates possible
span->length = n;
pagemap_.set(span->start + n - 1, span);
}
ASSERT(Check());
return span;
}
AllocLarge函数负责从heap的large_区去切割出n大小的span中Alloc出length为n的pages,并从large_列表中找到一个length >=n,最小而且startsize是最下面的span。先从normal list在从return list里面找,然后通过carve切割出来。
Span* PageHeap::AllocLarge(Length n) {
// find the best span (closest to n in size).
// The following loops implements address-ordered best-fit.
Span *best = NULL;
// Search through normal list
for (Span* span = large_.normal.next;
span != &large_.normal;
span = span->next) {
if (span->length >= n) {
if ((best == NULL)
|| (span->length < best->length)
|| ((span->length == best->length) && (span->start < best->start))) {
best = span;
ASSERT(best->location == Span::ON_NORMAL_FREELIST);
}
}
}
// Search through released list in case it has a better fit
for (Span* span = large_.returned.next;
span != &large_.returned;
span = span->next) {
if (span->length >= n) {
if ((best == NULL)
|| (span->length < best->length)
|| ((span->length == best->length) && (span->start < best->start))) {
best = span;
ASSERT(best->location == Span::ON_RETURNED_FREELIST);
}
}
}
return best == NULL ? NULL : Carve(best, n);
}
GrowHeap函数通过TCMalloc_SystemAlloc来grow heap,首先会对要求分配的size做个处理,如果size大于kMinSystemAlloc(256),那么直接调用TCMalloc_SystemAlloc分配需要的size,否则分配kMinSystemAlloc size。如果分配不成功,那么判断是不是分配的要求大于我的要求(n
bool PageHeap::GrowHeap(Length n) {
ASSERT(kMaxPages >= kMinSystemAlloc);
if (n > kMaxValidPages) return false;
Length ask = (n>kMinSystemAlloc) ? n : static_cast
size_t actual_size;
void* ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);
if (ptr == NULL) {
if (n < ask) {
// Try growing just "n" pages
ask = n;
ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);
}
if (ptr == NULL) return false;
}
如果上述过程中分配成功,调用RecordGrowth在stacktrace中进行记录,如果符合条件old_system_bytes < kPageMapBigAllocationThreshold&& stats_.system_bytes >= kPageMapBigAllocationThreshold,那么为了防止pagemap metadata内存碎片,在一次性的分配一部分内存给pagemap。然后判断pagemap是否还有entries,如果有那么通过NewSpan生成一个Span然后通过RecordSpan将他加入pagemap_,最后调用Delete函数将这个Span返回给heap管理。
ask = actual_size >> kPageShift;
RecordGrowth(ask << kPageShift);
uint64_t old_system_bytes = stats_.system_bytes;
stats_.system_bytes += (ask << kPageShift);
const PageID p = reinterpret_cast
ASSERT(p > 0);
// If we have already a lot of pages allocated, just pre allocate a bunch of
// memory for the page map. This prevents fragmentation by pagemap metadata
// when a program keeps allocating and freeing large blocks.
if (old_system_bytes < kPageMapBigAllocationThreshold
&& stats_.system_bytes >= kPageMapBigAllocationThreshold) {
pagemap_.PreallocateMoreMemory();
}
// Make sure pagemap_ has entries for all of the new pages.
// Plus ensure one before and one after so coalescing code
// does not need bounds-checking.
if (pagemap_.Ensure(p-1, ask+2)) {
// Pretend the new area is allocated and then Delete() it to cause
// any necessary coalescing to occur.
Span* span = NewSpan(p, ask);
RecordSpan(span);
Delete(span);
ASSERT(Check());
return true;
} else {
// We could not allocate memory within "pagemap_"
// TODO: Once we can return memory to the system, return the new span
return false;
}
}