Chinaunix首页 | 论坛 | 博客
  • 博客访问: 68145
  • 博文数量: 19
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 239
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-08 15:35
文章分类

全部博文(19)

文章存档

2012年(2)

2011年(17)

我的朋友

分类: LINUX

2011-10-08 16:11:25

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<

           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<

                 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(object)) = span->objects;

    span->objects = object;

  }

}               

 

阅读(1302) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~