前言
对于 malloc 过程,以 __libc_malloc 函数为入口开始分析,对于 free 过程,以
__libc_malloc (size_t bytes)
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;
}
tcache_init(viod)
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_perthread_struct & tcache_entry
/* 管理 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;
tcache_shutting_down
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);
}