常规意义上,我们对 malloc / free 的理解是,我们通过这两个 API 在进程中调用,用来向操作系统申请内存。

那你有没有想过 malloc / free 是如何工作的呢。

前面的章节中我们提到,malloc 申请得到的内存,都会带上 Cookie 用于记录这块内存的边界。为了减少 malloc 带来的 overhead,在 GNU 中提出了使用链表来负责内存分配与回收的方式。那么 malloc / free 又是如何管理内存的呢。

Call Stack

在讲 malloc 之前,有必要先了解一下一个 CPP 程序是如何运行的。

上图左是 VC6 CPP 在运行的时候的调用栈,由下往上看

  1. 内核相关调用
  2. 调用 mainCRTStartup 函数,调用 C Runtime,分配内存,初始化 C 的标准库等
  3. 调用 main 函数
  4. 调用 exit 函数,退出和处理相关内容

同样,VC10 CPP 的 call stack 也差不多,只不过在 mainCRTStartup 函数中,去掉了部分内容。

这一部分有区别的内容就是 SBH(Small Block Heap)的相关内容。而在 VC10 中,SBH 的相关内容已经由 windows 操作系统API HeapAlloc 提供了,所以后续就移除掉了。见上图右。

mainCRTStartup

_heap_init

见上图左,标记1处。在进入 mainCRTStartup 之后,会首先调用 _heap_init 函数,CRT会先为自己建立一个 _crtheap (一开始申请的 heap 大小是 4096 bytes,刚好是一个内存页的大小),然后再调用 _sbh_heap_init 函数,从中配置 SBH 所需的 headers(大小是16)。

下图就反馈了以上两个函数的细节。