分类: LINUX
2011-10-08 15:40:20
下面我们具体分析一下malloc和free过程。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_malloc的call会转去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;
}
}