```c // From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
#if IS_IN (libc) 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");
if (!__malloc_initialized) ptmalloc_init (); #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes = checked_request2size (bytes); if (tbytes == 0) { __set_errno (ENOMEM); return NULL; } size_t tc_idx = csize2tidx (tbytes);
MAYBE_INIT_TCACHE ();
DIAG_PUSH_NEEDS_COMMENT; if (tc_idx < mp_.tcache_bins && tcache != NULL && tcache->counts[tc_idx] > 0) { victim = tcache_get (tc_idx); return tag_new_usable (victim); } DIAG_POP_NEEDS_COMMENT; #endif
if (SINGLE_THREAD_P) { victim = tag_new_usable (_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);
victim = tag_new_usable (victim);
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))); return victim; }
Copy </details>
注意它将始终用 `tag_new_usable` 标记返回的指针,来自代码:
```c
void *tag_new_usable (void *ptr)
Allocate a new random color and use it to color the user region of
a chunk; this may include data from the subsequent chunk's header
if tagging is sufficiently fine grained. Returns PTR suitably
recolored for accessing the memory there.
_int_malloc
这是分配内存的函数,使用其他桶和顶部块。
它开始定义一些变量并获取请求的内存空间所需的实际大小:
快速堆
如果所需的大小在快速堆的范围内,尝试使用快速堆中的一个块。基本上,根据大小,它会找到有效块应该位于的快速堆索引,如果有,它会返回其中一个。
此外,如果启用了 tcache,它会用快速堆填充该大小的 tcache 桶 。
在执行这些操作时,会执行一些安全检查:
如果块未对齐:malloc(): unaligned fastbin chunk detected 2
如果前向块未对齐:malloc(): unaligned fastbin chunk detected
如果返回的块的大小因其在快速堆中的索引而不正确:malloc(): memory corruption (fast)
如果用于填充 tcache 的任何块未对齐:malloc(): unaligned fastbin chunk detected 3
malloc_consolidate
如果它不是一个小块,那么就是一个大块,在这种情况下调用 malloc_consolidate
以避免内存碎片。
未排序的堆
是时候检查未排序的堆以寻找潜在的有效块来使用。
开始
这从一个大的循环开始,该循环将沿着 bk
方向遍历未排序的堆,直到到达末尾(arena 结构),使用 while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
此外,每当考虑一个新块时都会进行一些安全检查:
如果块大小异常(太小或太大):malloc(): invalid size (unsorted)
如果下一个块大小异常(太小或太大):malloc(): invalid next size (unsorted)
如果下一个块指示的前一个大小与块的大小不同:malloc(): mismatching next->prev_size (unsorted)
如果不是 victim->bck->fd == victim
或者不是 victim->fd == av
(arena):malloc(): unsorted double linked list corrupted
由于我们总是检查最后一个,它的 fd
应该始终指向 arena 结构。
如果下一个块没有指示前一个块正在使用:malloc(): invalid next->prev_inuse (unsorted)
如果成功,返回块并结束,如果不成功,继续执行函数...
如果大小相等
继续从桶中移除块,以防请求的大小正好是块的大小:
如果 tcache 没有填满,将其添加到 tcache 中,并继续指示可以使用 tcache 块
_int_malloc
限制
在这一点上,如果某个块存储在 tcache 中并且可以使用且达到了限制,就返回一个 tcache 块 。
此外,如果达到了 MAX_ITERS ,则从循环中退出并以不同的方式获取一个块(顶块)。
如果设置了 return_cached
,则只需从 tcache 返回一个块以避免更大的搜索。
如果没有找到合适的块,继续
大块(下一个更大)
如果在确切的大块中没有任何可以使用的块,开始循环遍历所有下一个大块(从立即更大的开始),直到找到一个(如果有的话)。
分割块的剩余部分被添加到未排序的块中,last_reminder 被更新,并且执行相同的安全检查:
bck->fd-> bk != bck
: malloc(): corrupted unsorted chunks2
sysmalloc
sysmalloc 开始
如果 arena 为 null 或请求的大小太大(并且还有允许的 mmaps),则使用 sysmalloc_mmap
分配空间并返回。
sysmalloc 不是主区域
它首先会尝试扩展 之前的堆。如果不可能,则尝试分配一个新的堆 并更新指针以便能够使用它。
最后,如果这也不行,尝试调用**sysmalloc_mmap
**。
sysmalloc 主区域之前的错误 1
如果之前返回了 MORECORE_FAILURE
,请再次尝试使用 sysmalloc_mmap_fallback
分配内存
sysmalloc finale
完成分配,更新区域信息
Copy // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2921C3-L2943C12
if (( unsigned long ) av -> system_mem > ( unsigned long ) (av -> max_system_mem))
av -> max_system_mem = av -> system_mem;
check_malloc_state (av);
/* finally, do the allocation */
p = av -> top;
size = chunksize (p);
/* check that one of the above allocation paths succeeded */
if (( unsigned long ) (size) >= ( unsigned long ) (nb + MINSIZE))
{
remainder_size = size - nb;
remainder = chunk_at_offset (p , nb) ;
av -> top = remainder;
set_head (p , nb | PREV_INUSE | (av != & main_arena ? NON_MAIN_ARENA : 0 )) ;
set_head (remainder , remainder_size | PREV_INUSE) ;
check_malloced_chunk (av , p , nb) ;
return chunk2mem (p) ;
}
/* catch all failure paths */
__set_errno (ENOMEM);
return 0 ;
sysmalloc_mmap