Next we will analyze the malloc and free Processes in detail. The code for tc_malloc is as follows:
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 calls do_malloc_or_cpp_alloc to implement the malloc memory process, and CALLS mallochook: invokenewhook (if any) after the memory allocation ends, the implementation of mallochook: invokenewhook is relatively simple, as shown below:
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 mainly calls the corresponding allocation functions by distinguishing whether it is an allocation in C ++ or an allocation in 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 is set through the tc_set_new_mode function. The default value is 0. If the value is 1, the call of the tc_malloc process is switched to cpp_alloc. If the call fails, the standard std_new_handler is called. The following describes 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
// 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;
}
The do_malloc function first obtains the unique distribution zone of the thread through threadcache: getcache (). getcache first checks whether tsd_inited _ has been set to true, this variable is used to determine whether tcmalloc is initialized when pthread_keycreate cannot be correctly executed during process startup. If it is not initialized, initmodule is called for initialization.
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;
}
The initmodule () (src/thread_cache.cc) function first obtains the entire heap.
(Static: pageheap_lock), and then judge whether the initialization of tcmalloc has been done through the variable phinited. If not, call tatic: initstaticvars (); To perform global initialization.
Void threadcache: initmodule (){
Spinlockholder H (static: pageheap_lock ());
If (! Phinited ){
Static: initstaticvars ();
Threadcache_allocator.init ();
Phinited = 1;
}
}