1. malloc源码分析—ptmalloc
1.1 malloc_hook_ini
本文分析malloc的源码,首先从glibc开始,首先看malloc.c文件中的一段定义,
|
|
strong_alias
是GNU C中的定义,编译器判定这里malloc是__libc_malloc
的别名,__libc_malloc
定义在malloc.c中,
|
|
首先看atomic_forced_read
,
|
|
__typeof
是原始函数的返回类型,后面是一段汇编代码,”0”是零,即%0,引用时不可以加 %,只能input引用output,这里就是原子读,将__malloc_hook
的地址放入任意寄存器(r)再取出。__malloc_hook
的定义如下
|
|
weak_variable其实就是,
|
|
和编译器有关,这里不管它。__builtin_expect
其实就是告诉编译器if判断语句里大多数情况下的值,这样编译器可以做优化,避免过多的跳转。回到__libc_malloc
接下来就是调用malloc_hook_ini
进行内存的分配。malloc_hook_ini
定义在hooks.c中,
|
|
1.2 ptmalloc_init
ptmalloc_init用来对整个ptmalloc框架进行初始化,定义在arena.c中,
|
|
首先检查全局变量__malloc_initialized
是否大于等于0,如果该值大于0,表示ptmalloc已经初始化,如果改值为0,表示ptmalloc正在初始化,全局变量__malloc_initialized
用来保证全局只初始化ptmalloc一次。tsd_key_create
创建线程私有实例arena_key
,该私有实例保存的是分配区(arena)的malloc_state
实例指针。arena_key
指向的可能是主分配区的指针,也可能是非主分配区的指针,这里将调用ptmalloc_init()
的线程的arena_key
绑定到主分配区上。意味着本线程首选从主分配区分配内存。arena_key在glibc中是一个线程私有变量,
|
|
tsd_setspecific(arena_key, (void *) &main_arena);
就是__libc_tsd_MALLOC = &main_arena
thread_atfork用来设置进程在fork创建子进程时关于锁设置的各个函数,ptmalloc_lock_all
和ptmalloc_unlock_all
用来给父进程加锁解锁,ptmalloc_unlock_all2
用来给子进程调用以解锁。
|
|
其中,atfork_mem
是一个全局的fork时的函数子针结构体fork_handler,
|
|
__linkin_atfork
用于将刚刚构造的fork_handler添加进全局链表__fork_handlers
中而不用加锁,其实就是一个CAS锁,关于该锁,可以查阅网上资料,
|
|
catomic_compare_and_exchange_bool_acq
最后是一个宏定义,将之改写后如下
|
|
gcc会将这段代码进行编译,生成的代码无法被中断。因此简单说来,__linkin_atfork
就是将fork_handler
原子添加进全局链表__fork_handlers
中。
回到ptmalloc_init函数中,接下来就是进行环境变量的设置,__glibc_likely
和gcc的编译优化相关,不管他。_environ
就是__environ
,里面保存了环境变量,下面就是根据各个环境变量调用__libc_mallopt
进行设置,后面来看这个函数。
ptmalloc_init
然后获取__malloc_initialize_hook
函数指针并执行,由于该函数和malloc没有直接关系,这里不管它。最后将__malloc_initialized
设置为1,表是初始化完成。
1.3 __libc_mallopt
__libc_mallopt
定义在malloc.c中,
|
|
首先通过__malloc_initialized
判断如果ptmalloc还未初始化,就调用ptmalloc_init
进行初始化。malloc_consolidate
用来将fast bins中的chunk合并,并且里面会初始化主分配区,后面的章节会分析到这个函数。然后就根据传入的param_number
设置mp_
,mp_
代表ptmalloc的各个全局参数,其默认定义如下
|
|
这里不分析里面各个参数的意义,到后面用到时再来分析。malloc_hook_ini
最后会回调__libc_malloc
函数,这次__malloc_hook
为null,因此继续看下面的代码。
1.4 arena_get
接下来通过arena_get
获得一个分配区,arena_get
是个宏定义,定义在arena.c中,
|
|
arena_lookup
从私有变量里获取分配区指针,
|
|
tsd_getspecific
也是个宏定义,就是获取前面调用tsd_setspecific
设置的分配区指针,这里取出的可能是主分配去指针,也可能是非主分配去指针,然后调用arena_lock
对malloc_state
中的mutex
加锁。
|
|
获得分配去的指针后,就会调用_int_malloc
开始分配内存了,下一章分析这个函数。