tcmalloc do_free过程分析(2)

本文详细解释了如何将特定freelist中的对象批量释放至中央缓存,包括使用PopRange和InsertRange函数的操作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ReleaseToCentralCache将某个freelist中的obj全部释放回centralcache,函数比较简单,如下所示,主要是通过一个while循环将freelist中的obj按照num_objects_to_move一批批的通过PopRange pop出来,然后转移到central_cachecentral_cache调用InsertRange将每一批obj插入相应的freelist

void ThreadCache::ReleaseToCentralCache(FreeList* src, size_t cl, int N) {

  ASSERT(src == &list_[cl]);

  if (N > src->length()) N = src->length();

  size_t delta_bytes = N * Static::sizemap()->ByteSizeForClass(cl);

     

  // We return prepackaged chains of the correct size to the central cache.

  // TODO: Use the same format internally in the thread caches?

  int batch_size = Static::sizemap()->num_objects_to_move(cl);

  while (N > batch_size) {

    void *tail, *head;

    src->PopRange(batch_size, &head, &tail);

    Static::central_cache()[cl].InsertRange(head, tail, batch_size);

    N -= batch_size;

  }

  void *tail, *head;

  src->PopRange(N, &head, &tail);

  Static::central_cache()[cl].InsertRange(head, tail, N);

  size_ -= delta_bytes;

}

InsertRange函数根据传入的obj的数量判断是不是正好为转移一批的size,如果是且tc_slots_还有空那么直接插入tc_slots_,否则将调用ReleaseListToSpans释放到Span队列中。

void CentralFreeList::InsertRange(void *start, void *end, int N) {

  SpinLockHolder h(&lock_);

  if (N == Static::sizemap()->num_objects_to_move(size_class_) &&

    MakeCacheSpace()) {

    int slot = used_slots_++;

    ASSERT(slot >=0);

    ASSERT(slot < kNumTransferEntries);

    TCEntry *entry = &tc_slots_[slot];

    entry->head = start;

    entry->tail = end;

    return;

  }

  ReleaseListToSpans(start);

}

ReleaseListToSpansRange中的每个obj调用ReleaseToSpansReleaseToSpan首先根据objaddr获取obj所在的Span的地址,然后通过Span-> objects是否为NULL判断本Span中是否还有空闲的obj,如果没有,那么代表着本Spanempty队列中,现在有obj release了,那么就得将这个Span转移到nonempty队列中,以表示本Span还有可用的obj

void CentralFreeList::ReleaseToSpans(void* object) {

  Span* span = MapObjectToSpan(object);

  ASSERT(span != NULL);

  ASSERT(span->refcount > 0);

 

  // If span is empty, move it to non-empty list

  if (span->objects == NULL) {

    tcmalloc::DLL_Remove(span);

    tcmalloc::DLL_Prepend(&nonempty_, span);

    Event(span, 'N', 0);

  }

下面开始将obj插入Span中,首先对Span现有的obj进行遍历,以确保当前需要释放的obj不在Span空闲obj队列中。

  // The following check is expensive, so it is disabled by default

  if (false) {

    // Check that object does not occur in list

    int got = 0;

    for (void* p = span->objects; p != NULL; p = *((void**) p)) {

      ASSERT(p != object);

      got++;

    }

    ASSERT(got + span->refcount ==

           (span->length<<kPageShift) /

           Static::sizemap()->ByteSizeForClass(span->sizeclass));

  }

这里看是设置整个centeral cache当前freelist中的空闲obj的数量(counter_++)和当前Span中在使用obj的数量(span->refcount--;),如果本Span中已经没有在使用的obj了那么通过pageheapDelete函数将本Span还给pageheap。否则将需要释放的obj加入Spanobject list中,并放在头上。

  counter_++;

  span->refcount--;

  if (span->refcount == 0) {

    Event(span, '#', 0);

    counter_ -= ((span->length<<kPageShift) /

                 Static::sizemap()->ByteSizeForClass(span->sizeclass));

    tcmalloc::DLL_Remove(span);

 

    // Release central list lock while operating on pageheap

    lock_.Unlock();

    {

      SpinLockHolder h(Static::pageheap_lock());

      Static::pageheap()->Delete(span);

    }

    lock_.Lock();

  } else {

    *(reinterpret_cast<void**>(object)) = span->objects;

    span->objects = object;

  }

}               


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值