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

相关推荐
HideF7 小时前
Linux sudo
linux
FlightYe7 小时前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
蹊黎8 小时前
Linux 下用 C 语言实现进度条
linux·c语言·单片机
牛马鸡niumasi10 小时前
【Linux】C语言文件操作
linux
say_fall10 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++
爱聊灵光的维C10 小时前
从看见世界到重构认知:在视觉与硬件的交汇处,寻找我们这代人的北极星
c语言·物联网·计算机视觉·重构·硬件工程·射频工程
wacsii10 小时前
【Linux进程(一)】Linux 进程初探:操作系统如何管理进程?fork() 为什么返回两次?
linux·运维·服务器
AI+程序员在路上11 小时前
RV1126B 上支持的模型及全流程应用--从CNN及语音到 LLMVLM 与跨平台选型
linux·c语言·人工智能
默|笙11 小时前
【Linux网络】传输层协议TCP(1)---TCP报文介绍
linux·网络·tcp/ip
相思难忘成疾11 小时前
从零搭建 Kubernetes 1.30 集群:kubeadm 部署一主多从实战(RHEL 9.3 + Docker + flannel)
linux·运维·kubernetes