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的?

相关推荐
旖旎夜光14 小时前
Linux(9)
linux·学习
喵了meme16 小时前
Linux学习日记24:Linux网络编程基础
linux·网络·学习
whlqjn_121116 小时前
linux下使用SHC对Shell脚本进行封装和源码隐藏
linux·centos
weixin_4624462316 小时前
K8s 集群部署基础:Linux 三节点 SSH 互信(免密登录)配置指南
linux·kubernetes·ssh
Hard but lovely17 小时前
Linux: 线程同步-- 基于条件变量 &&生产消费模型
linux·开发语言·c++
m0_7381207217 小时前
应急响应——知攻善防靶场Linux-1详细应急过程
linux·运维·服务器·网络·web安全·ssh
Guistar~~17 小时前
【Linux驱动开发IMX6ULL】WS73 驱动移植的详细教程基于USB协议--WIFi网卡、蓝牙BLE、星闪SLE
linux·驱动开发
GHL28427109017 小时前
无法连接服务端socket
linux·服务器·网络
阿华hhh18 小时前
项目(购物商城)
linux·服务器·c语言·c++