_libc_free

  1. 先检查是否有钩子函数,有则调用并返回。

  2. 如果是 mmap 分配的 chunk,则用 munmap 将其释放,如果释放的 chunk 大小大于 mmap 分配的阈值,且未关闭动态调整阈值开关,则调整一下 mmap 的阈值为当前 chunk 大小。

  3. 调用 _int_free 释放内存。

  4. chunk_size < 128B ,且 chunk 不与 top chunk 相邻则放入 fast bins 中,这里不会加锁,而是用的 CAS,返回。

  5. 加锁分配区,前一个 chunk 若空闲,则合并。

  6. 后一个 chunk 若为 top chunk ,则将其合并到 top chunk 中,若不是也合并,将其放到 unosrted bin

  7. 如果合并的 chunk 大于 64KB,则开始整合 fast binsunsorted bin ,若 top chunk 的大小 大过 收缩阈值了,默认为 128K ,则收缩堆,也就是还给内核。

  8. 也就是说 释放内存回内核 需要两个条件, chunk_size > 64KB,且 top chunk 大于收缩阈值,则释放。

void
__libc_free (void *mem)
{mstate ar_ptr;mchunkptr p;                          /* chunk corresponding to mem */void (*hook) (void *, const void *)= atomic_forced_read (__free_hook);if (__builtin_expect (hook != NULL, 0)){(*hook)(mem, RETURN_ADDRESS (0));return;}if (mem == 0)                              /* free(0) has no effect */return;p = mem2chunk (mem);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;}MAYBE_INIT_TCACHE ();ar_ptr = arena_for_chunk (p);_int_free (ar_ptr, p, 0);
}

__libc_free__lib_malloc一样首先查看是否有__free_hook函数,如果有就直接调用,这里假设没有默认函数可用。接下来通过mem2chunk将虚拟内存的指针mem转换为对应的chunk指针p

​ 因为一个使用中的chunk结构体只使用其prev_sizesize字段,因此这里只需要减去2*SIZE_SZ。接下来,chunk_is_mmapped用来检查size最低三位中的标志位,判断该chunk是否是由mmap分配的,如果是,就调用munmap_chunk释放该chunk并返回,在调用munmap_chunk之前,需要更新全局的mmap阀值和收缩阀值。

munmap_chunk

static void
munmap_chunk (mchunkptr p)
{size_t pagesize = GLRO (dl_pagesize);INTERNAL_SIZE_T size = chunksize (p);assert (chunk_is_mmapped (p));/* Do nothing if the chunk is a faked mmapped chunk in the dumpedmain arena.  We never free this memory.  */if (DUMPED_MAIN_ARENA_CHUNK (p))return;uintptr_t mem = (uintptr_t) chunk2mem (p);uintptr_t block = (uintptr_t) p - prev_size (p);size_t total_size = prev_size (p) + size;/* Unfortunately we have to do the compilers job by hand here.  Normallywe would test BLOCK and TOTAL-SIZE separately for compliance with thepage size.  But gcc does not recognize the optimization possibility(in the moment at least) so we combine the two values into one beforethe bit test.  */if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0|| __glibc_unlikely (!powerof2 (mem & (pagesize - 1))))malloc_printerr ("munmap_chunk(): invalid pointer");atomic_decrement (&mp_.n_mmaps);atomic_add (&mp_.mmapped_mem, -total_size);/* If munmap failed the process virtual memory address space is in abad shape.  Just leave the block hanging around, the process willterminate shortly anyway since not much can be done.  */__munmap ((char *) block, total_size);
}

​ 首先将chunk转换为size,获得前一个chunk的指针block,计算这两个chunk的size之和至total_size,接着对全局结构mp_进行相应的设置后,就通过__munmap释放这两个chunk。根据malloc的源码可知,由mmap分配的chunk是独立的,大部分情况下,p->prev_size为0,因此这里还是释放一个chunk,特殊情况下需要释放两个chunk,特殊情况请参考_int_malloc中的代码。

__munmap再往下就是系统调用了。

堆内存(7)——内存释放入口函数_lib_free相关推荐

  1. Linux内存管理内存映射以及通过反汇编定位内存错误问题

    提到C语言,我们知道C语言和其他高级语言的最大的区别就是C语言是要操作内存的! 我们需要知道--变量,其实是内存地址的一个抽像名字罢了.在静态编译的程序中,所有的变量名都会在编译时被转成内存地址.机器 ...

  2. [内核内存] [arm64] 内存回收2---快速内存回收和直接内存回收

    文章目录 内存紧张回收 快速内存回收 struct scan_control结构体 __node__reclaim函数介绍 快速内存回收注意事项和小结 直接内存回收 __perform_reclaim ...

  3. fork练习、从进程角度考虑堆区内存申请与释放的有关问题

    1.fork练习 1.1代码1; int main( int argc, char* argv[], char* envp[]) {int i = 0;for( ; i < 2; i++ ){f ...

  4. 单例中的堆内存是否需要释放? 何时释放?

    对于大多数程序员来说, 单例模式几乎就是第一个熟悉的设计模式. 我们看到单例模式中经常有new,  但没有看见delete, 这样不会内存泄露吗? 于是, 我想问, 单例中的堆内存是否需要释放? 何时 ...

  5. 二维数组的动态内存申请,采用子函数的方式 为二级指针申请内存,和释放内存

    原理:二级指针,行指针+列指针 照着葫芦画瓢就行. 方法一:用c语言malloc实现 #include<cstdio> #include<iostream> #include& ...

  6. C++堆内存空间详解(释放内存、内存泄露)

    家里要来客人了,我们要给客人们泡茶.如果规定只能在确定来几位客人之前就把茶泡好,这就会显得很尴尬:茶泡多了会造成浪费,泡少了怕怠慢了客人.所以,最好的方法就是等知道了来几位客人再泡茶,来几位客人就泡几 ...

  7. 【C 语言】结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )

    文章目录 一.结构体中嵌套一级指针 1.声明 结构体类型 2.为 结构体 变量分配内存 ( 分配内存时先 为结构体分配内存 然后再为指针分配内存 ) 3.释放结构体内存 ( 释放内存时先释放 指针成员 ...

  8. LwIP 之五 详解动态内存管理 内存堆(mem.c/h)

    写在前面   目前网上有很多介绍LwIP内存的文章,但是绝大多数都不够详细,甚至很多介绍都是错误的!无论是代码的说明还是给出的图例,都欠佳!下面就从源代码,到图例详细进行说明.   目前,网络上多数文 ...

  9. 6.堆(动态内存 heap)的初始化和使用

    堆:先进先出 FIFO:First in first out  手动分配.释放 栈:后进先出 FILO:First in last  out  自动分配释放 裸机情况下使用动态内存heap:在启动文件 ...

最新文章

  1. ZED~Windows
  2. Openstack组建部署 — Environment of Controller Node
  3. pycharm 如何设置文件头信息?信息模板 头文件 coding: utf-8
  4. RedHat 6 安装配置Tomcat 7
  5. [渝粤教育] 西南科技大学 计算机工业控制 在线考试复习资料
  6. iptables 开放远程_远程FX正式上市 指导价11.99万-12.99万元_搜狐汽车
  7. Oracle PL/SQL匿名块(二)
  8. putty登录到shell.sourceforge.net方法
  9. 怎样永久关闭Win10自动更新_win10官网
  10. Linux搭建FTP服务器
  11. pip 安装GPU版本pytorch 与cuda下载
  12. 给基于HEXO的博客添加gitter在线交流
  13. Seventh season fifteenth episode,Joey got a new brain??????
  14. **[UE4技巧]** UE4 的导入模型人物处理(下) — 全面替换小白人,实现人物模型自由
  15. python求最小公倍数
  16. Response设置响应数据功能介绍及重定向
  17. kali系统的u盘安装过程_kali linux怎么安装u盘启动
  18. 软件著作权申请注意事项——常见问题
  19. 2、自写VBA函数2<高德测距>用VB网抓高德地图货车导航距离
  20. 炸裂,Cocos元宇宙生态基建项目!这个Demo从角色捏脸乳摇到场景氛围特效网络帧同步一应俱全........

热门文章

  1. LeetCode_904 水果成篮
  2. mysql 复合索引(联合索引) a b c的使用
  3. Mac 重命名快捷键
  4. dvwa中的xss(跨站脚本)攻击
  5. 深入理解计算机系统(2.8)---浮点数的舍入,Java中的舍入例子以及浮点数运算(重要)
  6. Kubernetes更优雅的监控工具Prometheus Operator
  7. 雅虎的站长天下要关门了,哎,真是悲哀
  8. WNM2020-3/TR MOS场效应晶体管
  9. 夸克链创始人周期:把区块链的好处带给千家万户
  10. 微信小程序实现跑马灯效果(完整代码)