感谢这篇文章 让我深入理解了malloc的具体实现
首先讲解几个数据结构
heap_info 通过循环链表串接
/* A heap is a single contiguous memory region holding (coalesceable)
malloc_chunks. It is allocated with mmap() and always starts at an
address aligned to HEAP_MAX_SIZE. */
typedef struct _heap_info
{
mstate ar_ptr; /* Arena for this heap. */ //指向mstate结构 这个结构用以描述arena 不管是main还是thread arena 都只有一个mstate结构
struct _heap_info *prev; /* Previous heap. */ //指向上一个heap_info结构 只对于thread_arena而言 可能存在多个heap 每个heap用一个heap_info结构加以表示
size_t size; /* Current size in bytes. */ //heap_info结构的大小
size_t mprotect_size; /* Size in bytes that has been mprotected
PROT_READ|PROT_WRITE. */
/* Make sure the following data is properly aligned, particularly
that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
MALLOC_ALIGNMENT. */
char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK]; //用于对齐的 可以不用管
} heap_info;
malloc_state 即mstate 相当于代表一个arena的数据结构 通过单循环链表连接不同的arena
malloc_state 即mstate结构
struct malloc_state
{
/* Serialize access. */
mutex_t mutex;
/* Flags (formerly in max_fast). */
int flags;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS]; //存放fast bin的数组链表 这是个单链表结构
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top; //指向top chunk
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder; //指向last remainder
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2]; //NBINS定义为128 由于在bins数组中的每个bin都有着一个fd和bk的指针 所以要乘2
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE]; //用于快速查找对应index的bin是否为空的一个位图
/* Linked list */
struct malloc_state *next; //指向下一个arena arena之间通过单循环链表构成的 所以只有一个next指针
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
malloc_chunk结构
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ //当上个块处于free状态的时候代表上个块的大小
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ //size代表本chunk的大小 sizeof(currentChunk)
struct malloc_chunk* fd; /* double links -- used only if free. */ //仅用于free的块 fd和bk指针用于被bin所串连从而进行管理
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ //这两个字段仅用于large freed chunk 即只在large freed chunk中出现 这两个域用于快速索引到下一个size的large chunk
struct malloc_chunk* bk_nextsize;
};
ptmalloc初始化流程
malloc_hook_ini初始化会走这个流程
static void * malloc_hook_ini (size_t sz, const void *caller){
__malloc_hook = NULL;
ptmalloc_init ();
return __libc_malloc (sz);
}
首先将 _malloc_hook 这个全局变量设置为null,然后调用ptmalloc_init(),最后调用 __libc_malloc函数。
ptmalloc_init
该函数的实现在arena.c中
static void ptmalloc_init(void) {
if (__malloc_initialized >= 0)
return;
__malloc_initialized = 0;
tsd_key_create(&arena_key, NULL);
tsd_setspecific(arena_key, (void *) &main_arena);
thread_atfork(ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
const char *s = NULL;
if (__glibc_likely(_environ != NULL)) {
char **runp = _environ;
char *envline;
while (__builtin_expect((envline = next_env_entry(&runp)) != NULL, 0)) {
size_t len = strcspn(envline, "=");
if (envline[len] != '=')
continue;
switch (len) {
case 6:
if (memcmp(envline, "CHECK_", 6) == 0)
s = &envline[7];
break;
case 8:
if (!__builtin_expect(__libc_enable_secure, 0)) {
if (memcmp(envline, "TOP_PAD_", 8) == 0)
__libc_mallopt(M_TOP_PAD, atoi(&envline[9]));
else if (memcmp(envline, "PERTURB_", 8) == 0)
__libc_mallopt(M_PERTURB, atoi(&envline[9]));
}
break;
case 9:
if (!__builtin_expect(__libc_enable_secure, 0)) {
if (memcmp(envline, "MMAP_MAX_", 9) == 0)
__libc_mallopt(M_MMAP_MAX, atoi(&envline[10]));
else if (memcmp(envline, "ARENA_MAX", 9) == 0)
__libc_mallopt(M_ARENA_MAX, atoi(&envline[10]));
}
break;
case 10:
if (!__builtin_expect(__libc_enable_secure, 0)) {
if (memcmp(envline, "ARENA_TEST", 10) == 0)
__libc_mallopt(M_ARENA_TEST, atoi(&envline[11]));
}
break;
case 15:
if (!__builtin_expect(__libc_enable_secure, 0)) {
if (memcmp(envline, "TRIM_THRESHOLD_", 15) == 0)
__libc_mallopt(M_TRIM_THRESHOLD, atoi(&envline[16]));
else if (memcmp(envline, "MMAP_THRESHOLD_", 15) == 0)
__libc_mallopt(