对于 malloc 过程,以 __libc_malloc 函数为入口开始分析,对于 free 过程,以
void * __libc_malloc (size_t bytes) { mstate ar_ptr; void *victim; _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, "PTRDIFF_MAX is not more than half of SIZE_MAX"); /* 如果存在__malloc_hook,则调用 hook 函数 */ void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) return (*hook)(bytes, RETURN_ADDRESS (0)); /* 使用 tcache 机制的情况 */ #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes; /* 判断请求分配字节的大小,在 64 位的情况下,bytes 不能大于 0x7fffffffffffffff;*/ /* 在 32 位的情况下,bytes 不能超过 0x7fffffff。函数中也会调用 request2size 来 */ /* 计算 bytes 数据需要分配的内存大小,当 bytes 数据的大小比最小 chunk 要还小时,*/ /* 按最小 chunk 的大小分配;当 bytes 数据的大小比最小 chunk 大时,则分配满足内存 */ /* 对齐要求的最小大小。将分配的大小赋值给 tbytes 返回。 */ if (!checked_request2size (bytes, &tbytes)) { __set_errno (ENOMEM); return NULL; } /* 计算 tbytes 大小所对应的 tcache 下标 */ size_t tc_idx = csize2tidx (tbytes); /* 如果 tcache 还没有被创建,则调用 tcache_init() 初始化 tcache */ MAYBE_INIT_TCACHE (); DIAG_PUSH_NEEDS_COMMENT; if (tc_idx < mp_.tcache_bins && tcachef && tcache->counts[tc_idx] > 0) { return tcache_get(tc_idx); } DIAG_POP_NEEDS_COMMENT; #endif if (SINGLE_THREAD_P) { victim = _int_malloc (&main_arena, bytes); assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || &main_arena == arena_for_chunk (mem2chunk (victim))); return victim; } arena_get (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); /* Retry with another arena only if we were able to find a usable arena before. */ if (!victim && ar_ptr != NULL) { LIBC_PROBE (memory_malloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); } if (ar_ptr != NULL) __libc_lock_unlock (ar_ptr->mutex); assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))); return victim; }
static void tcache_init(void) { mstate ar_ptr; void *victim = 0; /* 计算 tcahce_perthread_struct 结构大小 */ const size_t bytes = sizeof (tcache_perthread_struct); if (tcache_shutting_down) return; arena_get (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); if (!victim && ar_ptr != NULL) { ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); } if (ar_ptr != NULL) __libc_lock_unlock (ar_ptr->mutex); /* In a low memory situation, we may not be able to allocate memory - in which case, we just keep trying later. However, we typically do this very early, so either there is sufficient memory, or there isn't enough memory to do non-trivial allocations anyway. */ if (victim) { tcache = (tcache_perthread_struct *) victim; memset (tcache, 0, sizeof (tcache_perthread_struct)); } }
/* 管理 tcache 的结构 */ typedef struct tcache_perthread_struct { uint16_t counts[TCACHE_MAX_BINS]; /* 统计数组中每个下标有多少对应的 chunk ,TCHACHE_MAX_BINS 的值一般是 64 */ tcache_entry *entries[TCACHE_MAX_BINS]; /* 指向不同 tcache 的指针数组*/ } tcache_perthread_struct; /* tcache 的基本结构,通过单项链表连接 */ typedef struct tcache_entry { struct tcache_entry *next; /* 指向下一个 tcache 的指针 */ /* This field exists to detect double frees. */ struct tcache_perthread_struct *key; /* 新增的防止 tcache double free 的机制 */ } tcache_entry;
static void tcache_thread_shutdown (void) { int i; tcache_perthread_struct *tcache_tmp = tcache; /* tcahce 不存在的情况下直接返回 */ if (!tcache) return; /* Disable the tcache and prevent it from being reinitialized. */ /* 禁用tcache,防止它被重新初始化 */ tcache = NULL; tcache_shutting_down = true; /* tcache_shutting_down 的值默认值为 faluse */ /* Free all of the entries and the tcache itself back to the arena heap for coalescing. */ /* 释放所有的 tcache ,以便进行合并 */ /* 外层 for 循环遍历 tcache 指针数组,数组的每个下标对应不同大小的 tcache */ for (i = 0; i < TCACHE_MAX_BINS; ++i) { /* 内层 while 循环遍历整个 tcache 点链表,也就是相同大小的 tcache */ while (tcache_tmp->entries[i]) { tcache_entry *e = tcache_tmp->entries[i]; tcache_tmp->entries[i] = e->next; __libc_free (e); } } __libc_free (tcache_tmp); }