释放内存块
__libc_free
类似于 malloc,free 函数也有一层封装,命名格式与 malloc 基本类似。代码如下
void __libc_free(void *mem) {
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
// 判断是否有钩子函数 __free_hook
void (*hook)(void *, const void *) = atomic_forced_read(__free_hook);
if (__builtin_expect(hook != NULL, 0)) {
(*hook)(mem, RETURN_ADDRESS(0));
return;
}
// free NULL没有作用
if (mem == 0) /* free(0) has no effect */
return;
// 将mem转换为chunk状态
p = mem2chunk(mem);
// 如果该块内存是mmap得到的
if (chunk_is_mmapped(p)) /* release mmapped memory. */
{
/* See if the dynamic brk/mmap threshold needs adjusting.
Dumped fake mmapped chunks do not affect the threshold. */
if (!mp_.no_dyn_threshold && chunksize_nomask(p) > mp_.mmap_threshold &&
chunksize_nomask(p) <= DEFAULT_MMAP_THRESHOLD_MAX &&
!DUMPED_MAIN_ARENA_CHUNK(p)) {
mp_.mmap_threshold = chunksize(p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
LIBC_PROBE(memory_mallopt_free_dyn_thresholds, 2,
mp_.mmap_threshold, mp_.trim_threshold);
}
munmap_chunk(p);
return;
}
// 根据chunk获得分配区的指针
ar_ptr = arena_for_chunk(p);
// 执行释放
_int_free(ar_ptr, p, 0);
}_int_free
函数初始时刻定义了一系列的变量,并且得到了用户想要释放的 chunk 的大小
简单的检查
其中
fast bin
如果上述检查都合格的话,判断当前的 bin 是不是在 fast bin 范围内,在的话就插入到 fastbin 头部,即成为对应 fastbin 链表的第一个 free chunk。
合并非 mmap 的空闲 chunk
只有不是 fast bin 的情况下才会触发unlink
首先我们先说一下为什么会合并chunk,这是为了避免heap中有太多零零碎碎的内存块,合并之后可以用来应对更大的内存块请求。合并的主要顺序为
先考虑物理低地址空闲块
后考虑物理高地址空闲块
合并后的 chunk 指向合并的 chunk 的低地址。
在没有锁的情况下,先获得锁。
轻量级的检测
释放填充
后向合并-合并低地址 chunk
下一块不是top chunk-前向合并-合并高地址chunk
需要注意的是,如果下一块不是 top chunk ,则合并高地址的 chunk ,并将合并后的 chunk 放入到unsorted bin中。
下一块是 top chunk-合并到 top chunk
向系统返还内存
释放 mmap 的chunk
systrim
heap_trim
munmap_chunk
Last updated