Note
malloc 底层用什么系统调用?大小内存一样吗?
说明 glibc 等常见实现里小块走 brk/sbrk 堆扩展、大块常走 mmap,以及阈值策略差异。
省流
malloc本身是 C 库中的用户态分配器,不是内核系统调用。真正向操作系统申请虚拟地址空间时,常见路径主要是brk/sbrk和mmap。二者不会在所有大小上无差别地使用同一个策略。以 glibc 的 ptmalloc 一类实现为例:较小的分配通常在进程堆上管理,堆通过
brk/sbrk上下移动 program break 来扩展或收缩;较大的分配常常直接mmap匿名映射,释放时再用munmap归还。分界阈值由实现决定,历史上常见量级是数十到数百 KB,且可配置,不能背成一个永远不变的常数。这样拆分的原因是:小对象分配极频繁,适合在用户态用 freelist/bin 复用,减少系统调用;大对象若长期留在堆中间,容易造成堆难以收缩和碎片问题,独立映射更利于整块归还。
分层关系
应用:malloc / free
|
v
C 库分配器(如 ptmalloc):管理 arena、chunk、bin
|
+-- 小块:扩展/使用主堆 -> brk / sbrk
+-- 大块:匿名映射 -> mmap / munmap
面试时要先说清:malloc 多数时候只是在已向内核要过的虚拟内存里做切分与复用;只有现有空间不够,或策略要求独立映射时,才会进入系统调用。
brk / sbrk
- 调整进程 data segment 末尾,即 program break。
- 适合作为“一块可伸展的堆”的底层来源。
free小块后,内存往往先回到分配器,不一定立刻把 break 降回去;只有高地址连续空闲到一定程度,才可能收缩堆。
mmap
- 可映射文件,也可做匿名映射(Anonymous Mapping)给内存分配用。
- 大块
malloc走mmap时,对应free通常可直接munmap,地址空间立刻还给内核。 - 也用于文件映射、共享内存等,不只服务
malloc。
大小内存是否用同一函数?
对应用来说都是 malloc;对操作系统来说,底层系统调用路径可以不同。
| 典型情况 | 更常见的内核接口 | 释放时 |
|---|---|---|
| 小分配 | 复用堆;必要时 brk/sbrk | 回到用户态 freelist,未必立刻归还内核 |
| 大分配 | mmap 匿名页 | 常直接 munmap |
具体阈值、是否启用 mmap、多线程 arena 细节因 libc 版本与编译选项而异。回答重点是机制,而不是背某一个魔法数字。
补充
- 即使用
mmap得到虚拟地址,物理页往往仍按缺页中断按需分配。 - 其他分配器(jemalloc、tcmalloc、musl malloc 等)同样是“用户态策略 + 少量系统调用”,但切分阈值和数据结构不同。
- 直接调用
mmap/brk可以自己做分配器;日常业务代码仍应优先使用库提供的malloc/free或语言运行时。