Free底层是怎么释放内存的

free 并不是把进程地址空间里的那一页直接"还"给操作系统,而是在用户态的堆管理器(glibc/ptmalloc、Windows CRT、jemalloc、tcmalloc 等)里完成一次记账操作。下面以 glibc 默认的 ptmalloc2 为例,把一次 free(ptr) 的完整链路拆开说明,其他实现思路大同小异。

1、先做"合法性"检查

如果 ptr == NULL,立即返回。

把指针往回偏移一个固定长度,拿到 chunk 头(下面会讲头里有什么)。

检查该 chunk 的魔数、对齐位、是否属于当前 arena 等,若发现异常直接 abort(经典的 "free(): invalid pointer" 报错就来自这里)。

2、怎么"知道"要释放多大

malloc 返回给用户的地址 并不是 真正从系统要到的起始地址,而是 紧接在头部后面的用户区。头部里保存了本次分配的大小(以及标志位、魔数等)。

free 时把传入的指针往前挪 8~16 B 就能拿到这个 "malloc_chunk" 头,从而读出 chunk_size [⁴][⁷]。

3、放进哪个"桶"------空闲链表

ptmalloc 把空闲块按大小分两类管理:

≤ 64 B 的精确大小 → fastbin[](LIFO,单向链表,不回填中央堆)。

65 B ~ 128 KB → small/large bin(双向链表,按大小排序)。

更大 → top chunk 直接 mmap,释放时用 munmap 还给内核。

根据大小把 chunk 链到对应 bin 里,并置标志位 IS_INUSE=0

4、立即合并(backward & forward coalesce)

检查物理相邻的前后两个 chunk 是否也是空闲:

是 → 把它们从各自 bin 中摘下,合并成一个更大的 chunk,再挂到对应的大 bin 里。

否 → 直接把自己挂进去。

这一步用来缓解外部碎片

5、是否"还"给操作系统

只有当 top chunk(堆顶最后一块空闲)大小超过 128 KB 时,ptmalloc 才会通过 brk(-size) 把尾部缩减,真正归还给内核;否则仍留在进程堆内,供下次 malloc 复用 [⁵][⁶]。

因此大多数 free 只是用户态记账,不会立刻体现为系统内存下降。

6、多线程场景

每个线程默认先绑定一个 arena(内存池),free 时若发现该 chunk 属于别的 arena,会把内存"搬家"到对应 arena 的空闲链表,再加互斥锁,防止并发破坏链表

所以,free 的"释放"本质是 "把一块内存从占用状态标成空闲,并挂进分配器的空闲链表";只有堆顶出现足够大的连续空闲块时,才会通过系统调用真正缩小进程地址空间。

Q: 是怎么找到chuck_size的?

相关推荐
tod1137 小时前
Makefile进阶(上)
linux·运维·服务器·windows·makefile·进程
阳光九叶草LXGZXJ7 小时前
达梦数据库-学习-50-分区表指定分区清理空洞率(交换分区方式)
linux·运维·数据库·sql·学习
zbliquan7 小时前
SS928v100远程ubuntu交叉编译开发环境搭建
linux·运维·ubuntu
我爱加班、、7 小时前
new Map()+Array.from()整理elementPlus的级联器数据
linux·前端·javascript
豆是浪个7 小时前
Linux(Centos 7.6)命令详解:top
linux·运维·服务器
历程里程碑7 小时前
Linxu14 进程一
linux·c语言·开发语言·数据结构·c++·笔记·算法
baidu_huihui8 小时前
`sudo DNF` 是 Linux 系统中以管理员权限执行 DNF 包管理命令的标准方式
linux·dnf
JiL 奥8 小时前
Nexus制品归档(c/c++项目)
c语言·c++
梵刹古音8 小时前
【C语言】 字符型变量
c语言·开发语言·嵌入式
峥嵘life8 小时前
Android 16 EDLA测试STS模块
android·大数据·linux·学习