tcmalloc do_free過程分析(2)

來源:互聯網
上載者:User

ReleaseToCentralCache將某個freelist中的obj全部釋放回centralcache,函數比較簡單,如下所示,主要是通過一個while迴圈將freelist中的obj按照num_objects_to_move一批批的通過PopRange
pop出來,然後轉移到central_cache,central_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);

}

ReleaseListToSpans對Range中的每個obj調用ReleaseToSpans。ReleaseToSpan首先根據obj的addr擷取obj所在的Span的地址,然後通過Span->
objects是否為NULL判斷本Span中是否還有閒置obj,如果沒有,那麼代表著本Span在empty隊列中,現在有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了那麼通過pageheap的Delete函數將本Span還給pageheap。否則將需要釋放的obj加入Span的object
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;

  }

}               

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.