现在的位置: 首页 > 综合 > 正文

Tcmalloc源码分析-3

2013年09月09日 ⁄ 综合 ⁄ 共 2331字 ⁄ 字号 评论关闭

下面我们具体分析一下mallocfree过程。tc_malloc的代码如下所示:

extern "C" PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW {

  void* result = do_malloc_or_cpp_alloc(size);

  MallocHook::InvokeNewHook(result, size);

  return result;

}

Tc_malloc调用do_malloc_or_cpp_alloc来实现malloc内存的过程,并在内存分配结束后调用MallocHook::InvokeNewHook(如果存在的话),MallocHook::InvokeNewHook的实现比较简单,如下所示:

inline void MallocHook::InvokeNewHook(const void* p, size_t s) {

  MallocHook::NewHook hook = MallocHook::GetNewHook();

  if (hook != NULL) (*hook)(p, s);

}

do_malloc_or_cpp_alloc主要通过区分是否为c++中的分配还是C中的分配,分别调用相应的分配函数:

inline void* do_malloc_or_cpp_alloc(size_t size) {

  return tc_new_mode ? cpp_alloc(size, true) : do_malloc(size);

}

tc_new_mode通过函数tc_set_new_mode设置,默认情况下为0,在为1的情况下,进程对tc_malloccall会转去cpp_alloc如果失败会调用标准的std_new_handler。下面我们主要讲一下do_malloc():

inline void* do_malloc(size_t size) {

  void* ret = NULL;

 

  // The following call forces module initialization

  ThreadCache* heap = ThreadCache::GetCache();

  if (size <= kMaxSize) {

    size_t cl = Static::sizemap()->SizeClass(size);

    size = Static::sizemap()->class_to_size(cl);

   

    if ((FLAGS_tcmalloc_sample_parameter > 0) && heap->SampleAllocation(size)) {

      ret = DoSampledAllocation(size);

    } else {

      // The common case, and also the simplest.  This just pops the

      // size-appropriate freelist, after replenishing it if it's empty.

      ret = CheckedMallocResult(heap->Allocate(size, cl));

    }

  } else {

    ret = do_malloc_pages(heap, size);

  } 

if (ret == NULL) errno = ENOMEM;

  return ret;

}

do_malloc函数首先首先通过ThreadCache::GetCache()去获取thread独有的分配区,GetCache首先判断tsd_inited_是否已经被置为true,采用这个变量主要是为了保证在进程启动时,在pthread_keycreate不能正确执行的情况下判断tcmalloc是否初始化,如果没有被初始化,则调用InitModule进行初始化。

inline ThreadCache* ThreadCache::GetCache() {

  ThreadCache* ptr = NULL;

  if (!tsd_inited_) {

  // Thread-specific key.  Initialization here is somewhat tricky

  // because some Linux startup code invokes malloc() before it

  // is in a good enough state to handle pthread_keycreate().

  // Therefore, we use TSD keys only after tsd_inited is set to true.

  // Until then, we use a slow path to get the heap object.

    InitModule();    

  } else {

    ptr = GetThreadHeap();

  }

  if (ptr == NULL) ptr = CreateCacheIfNecessary();

  return ptr;

}

 

InitModule()src/thread_cache.cc)函数首先获取整个heap
Static::pageheap_lock)的锁,然后通过变量phinited判断tcmalloc的初始化有没有做过,如果没有那么初始化那么开始调用tatic::InitStaticVars();进行全局初始化。

void ThreadCache::InitModule() {

  SpinLockHolder h(Static::pageheap_lock());

  if (!phinited) {

    Static::InitStaticVars();

    threadcache_allocator.Init();

    phinited = 1;

  }

}

抱歉!评论已关闭.