释放内存块

__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