一、内存布局
图 1:内存布局示意图(栈向下扩展,堆向上扩展)
由上图可知,栈至顶向下扩展,堆至底向上扩展。
二、brk(sbrk)和 mmap 函数
1. brk(sbrk)
在 Linux 系统中,malloc 底层主要通过 brk、sbrk 和 mmap 这几个系统调用来实现内存的分配和管理。
#include <unistd.h>
void *brk(const void *addr);
void *sbrk(intptr_t incr);
两者的作用是扩展 heap 的上界 brk。
brk():参数设置为新的 brk 上界地址,成功返回 0,失败返回 -1;如果 addr 大于当前的程序中断点,就会扩大数据段,分配新的内存;如果 addr 小于当前的程序中断点,就会缩小数据段,释放内存。sbrk():参数为申请内存的大小,返回 heap 新的上界 brk 的地址;当 increment 为正数时,堆顶指针会向高地址移动,分配内存;当 increment 为负数时,堆顶指针会向低地址移动,释放内存。
2. mmap
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
mmap() 进行内存分配(malloc)时一般使用后者,前者主要是进行文件映射。
mmap 分配内存比较直接,相对的开销也较大,释放也比较简单,通过 munmap 函数可以立即将内存归还给操作系统。
一般来说,当 malloc 申请的内存较小时,会使用 brk 或 sbrk 来扩展堆内存;而当申请的内存较大时(通常阈值为 128KB),会直接使用 mmap 在内存映射区申请内存。
但是,如果每次申请内存都调用这些接口的话,势必会影响系统的性能,并且也极容易产生内存碎片。所以 malloc 采用 ptmalloc(内存池管理机制)对内存的分配与回收进行管理。
3. ptmalloc
ptmalloc 会预先向操作系统申请一块内存供用户使用,当我们申请和释放内存的时候,ptmalloc 会将这些内存管理起来,并通过一些策略来判断是否将其回收给操作系统。


