在堆上分配内存:malloc和free
一般情况下,C程序使用malloc函数族在堆上分配和释放内存。较之brk和sbrk,这些函数具备不少优点:
属于C语言标准的一部分
更易于在多线程程序中使用
接口简单,允许分配小块内存
允许随意释放内存块,它们被维护于一张空闲内存列表中,在后续内存分配调用时循环使用
malloc函数在堆上分配参数size字节大小的内存,并返回指向新分配内存起始位置处的指针,其所分配的内存未经初始化。
#include <stdlib.h>
void *malloc(size_t size); /* Returns pointer to allocated memory on sucess, or NULL on error */
由于malloc的返回类型为void*,因而可以将其付赋给任意类型的C指针。malloc返回内存块所采用的的字节对齐方式,总是适宜于高效访问任何类型的C语言数据结构。在大多数硬件架构上,这意味着malloc是基于8字节或16字节边界来分配内存的。
SUSv3规定:调用malloc(0)要么返回NULL,要么是一小块可以(并且应该)用free释放的内存。Linux的malloc(0)遵循的是后者。
如果无法再分配内存(或许是因为已经达到了program break所能达到的地址上限),则malloc返回NULL,并设置errno以返回错误信息。
虽然分配内存失败的可能性很小,但所有对malloc以及后续提及的相关函数的调用都应对返回值进行错误检查。
free函数释放ptr参数所指向的内存块,该参数应该是之前由malloc,或者后续描述的其他堆内存分配函数之一所返回的地址。
#include <stdlib.h>
void free(void *ptr);
一般情况下,free并不降低program break的位置,而是将这块内存填加到空闲内存列表中,供后续的malloc函数循环使用。这么做是出于以下几个原因。
被释放的内存块通常会位于堆的中间,而非堆的顶部,因而降低program break是不可能的。
它最大限度地减少了程序必须执行的sbrk调用次数。
在大多数情况下,降低program break的位置不会对那些分配大量内存的程序有多少帮助,因为它们通常倾向于持有已经分配内存或是反复释放和重新分配内存,而非释放所有内存后再持续运行一段时间。
如果传给free的是一个空指针,那么函数将什么都不做。(换句话说,给free传入一个空指针并不是错误代码。)
在调用free后对参数ptr的任何使用,例如将其再次传递给free,将产生错误,并可能导致不可预知的结果。