Linux 下 malloc/free 完整底层原理:
内存管理 + ptmalloc 实现
这是 Linux 环境下 malloc/free 最核心、最底层的知识体系,
操作系统内存管理 →系统调用 →ptmalloc 实现原理
一、先搞懂:Linux 进程内存布局
malloc 分配的是进程虚拟内存,不是物理内存,这是理解底层的前提:
高地址
+------------------+
| 栈区(stack) | ← 自动变量,向下增长
| ↓ |
+------------------+
| 共享库/映射区 | ← mmap 分配大内存
+------------------+
| ↑ |
| 堆区(heap) | ← malloc 核心分配区,向上增长
+------------------+
| 未初始化数据段 |
+------------------+
| 初始化数据段 |
+------------------+
| 代码段 |
低地址
-
堆区 :malloc 主要使用的内存区域,由程序动态申请/释放
-
虚拟内存 :进程看不到物理内存,操作系统通过页表映射虚拟→物理内存
二、malloc 底层依赖的两个系统调用
malloc 不是直接操作物理内存,而是向操作系统申请虚拟内存,核心只有两个系统调用:
1. brk()
-
作用:抬高堆顶指针
program break,扩展堆区 -
适用:小内存分配(默认 < 128KB)
-
特点:轻量、速度快,内存归还给 OS 不及时
2. mmap()
-
作用:在文件映射区创建一块独立的匿名虚拟内存
-
适用:大内存分配(默认 ≥ 128KB)
-
特点:分配独立,free 时直接归还物理内存给操作系统
关键结论:
malloc 本身是用户态库函数,不直接管理物理内存;
真正向 OS 申请内存的是 brk/mmap,malloc 只是封装+内存管理。
三、ptmalloc:Linux 默认 malloc 实现(glibc)
Linux 标准 C 库(glibc)使用 ptmalloc 实现 malloc/free,它是最主流的内存分配器。
为什么需要 ptmalloc?直接用 brk/mmap 不行吗?
-
系统调用开销大(用户态→内核态切换)
-
频繁申请/释放小内存会造成内存碎片
-
物理内存频繁申请/释放会降低系统性能
ptmalloc 的核心设计:
向操作系统批量申请内存 ,在用户态管理内存池,给应用程序分配,减少系统调用。
四、ptmalloc 核心结构与原理
1. 核心概念
-
Arena(内存区)
-
主线程:主分配区(main arena),使用 brk 扩展堆
-
多线程:线程分配区(thread arena),使用 mmap 分配
-
作用:减少多线程锁竞争,提升并发性能
-
-
Chunk(内存块)
-
ptmalloc 管理内存的最小单位
-
你调用
malloc(16),实际分配的是一个 chunk -
chunk 包含:数据区 + 头部元信息(大小、是否空闲、前后指针)
-
-
Bin(空闲块链表)
-
ptmalloc 把空闲 chunk 按大小分类,用链表管理,核心 3 类:
-
fast bin:最快,极小内存(0~80B),free 不合并,只用于快速分配
-
small bin:小内存(80B~1KB),相同大小 chunk 链表
-
large bin:大内存(>1KB),按大小范围排序的链表
-
2. malloc 完整执行流程(最核心)
bash
malloc(size)
↓
计算真实chunk大小
↓
≥128KB ? → mmap → 返回
↓
<128KB → 查 fastbin
↓
找不到 → 查 small bin
↓
找不到 → 查 large bin
↓
找不到 → 用 top chunk
↓
不够 → brk 扩堆 / mmap
↓
切割chunk → 返回指针
必背核心结论
-
大内存直接 mmap,不走内存池,free 直接还给 OS
-
小内存优先复用空闲链表,尽量不触发系统调用
-
brk 扩展堆,top chunk 是最后兜底的分配空间
总结
• 先找缓存(fastbin → small bin → large bin)
• 再用堆顶(top chunk)
• 最后找操作系统(brk/mmap)
白话总结:
-
小内存:优先从空闲链表(bin) 复用内存,不触发系统调用
-
无空闲内存:用
brk向 OS 批量申请堆内存 -
大内存:直接用
mmap独立分配
3. free 完整执行流程
free 不是立刻把内存还给操作系统!
bash
free(ptr)
↓
校验指针合法 → 找到chunk头
↓
是否 mmap大内存? → 是 → munmap直接归还OS → 结束
↓
是否 Fastbin块?
├─ 是 → 加入Fastbin链表(不合并) → 结束
└─ 否 → 合并前后相邻空闲chunk
↓
是否堆顶Top Chunk?
├─ 是 → brk收缩堆,部分内存还给OS
└─ 否 → 插入Small/Large Bin空闲链表复用
核心 3 个面试考点
-
Fastbin 不合并碎片、不释放给内核,分配最快
-
普通 free 会合并相邻空闲块,降低内存碎片
-
只有「堆顶连续空闲内存」+「mmap 大内存」才会真正把内存还给操作系统,
常规小块 free 只是放回内存池,进程常驻内存不会变小。
关键结论:
-
fast bin/small bin 内存 :free 后不会还给 OS,留在进程内存池复用
-
mmap 分配的大内存 :free 时立刻归还 OS
-
只有堆顶的连续空闲内存,才会通过 brk 还给操作系统
五、ptmalloc 核心优缺点
优点
-
小内存分配极快(复用空闲 chunk,无系统调用)
-
多线程支持好(arena 机制减少锁竞争)
-
适配绝大多数应用场景(服务器、桌面软件)
缺点
-
内存驻留 :小内存 free 后不还给 OS,容易造成常驻内存高
-
内存碎片:长期运行后产生无法合并的碎片
-
高并发场景性能不如现代分配器(jemalloc/tcmalloc)
六、关键知识点总结
-
malloc 是用户态库函数 ,底层靠
brk(小内存)/mmap(大内存)向 OS 申请虚拟内存 -
Linux 默认使用 ptmalloc(glibc) 实现 malloc/free
-
ptmalloc 核心:内存池 + chunk + 空闲链表(bin)
-
free 不直接释放物理内存:
-
小内存:留在进程池复用
-
大内存(mmap):立即归还 OS
-
-
虚拟内存 ≠ 物理内存,OS 按需分配物理内存(缺页中断)
总结
-
底层支撑 :Linux 虚拟内存管理 +
brk/mmap系统调用是 malloc 的根基 -
核心实现 :ptmalloc 通过内存池、chunk、空闲链表实现高效内存分配
-
核心特性:小内存复用、大内存直接映射、free 延迟归还内存给操作系统
这就是 Linux 下 malloc/free 最完整的底层原理,覆盖了内存管理、系统调用、ptmalloc 实现全流程。