Tcmalloc源码简单分析(13)

我们在看看Carve函数,Carve函数将spannormal list中切出,返回给Populate。首先将spanlocation为置位为Span::IN_USE,然后判断这个span的长度是否真好为n,如果大于n那么将span切割成两个span,新切出来的span叫做leftover,然后通过RecordSpanspan添加到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函数负责从heaplarge_区去切割出n大小的spanAlloclengthnpages,并从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_SystemAllocgrow heap,首先会对要求分配的size做个处理,如果size大于kMinSystemAlloc256),那么直接调用TCMalloc_SystemAlloc分配需要的size,否则分配kMinSystemAlloc size。如果分配不成功,那么判断是不是分配的要求大于我的要求(n<ask)那么尝试TCMalloc_SystemAlloc n个页面。如果再次失败,那么返回失败。

bool PageHeap::GrowHeap(Length n) {

  ASSERT(kMaxPages >= kMinSystemAlloc);

  if (n > kMaxValidPages) return false;

  Length ask = (n>kMinSystemAlloc) ? n : static_cast<Length>(kMinSystemAlloc);

  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;

  }

如果上述过程中分配成功,调用RecordGrowthstacktrace中进行记录,如果符合条件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<uintptr_t>(ptr) >> kPageShift;

  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;

  }

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值